Compare commits

...

47 Commits
1.6.3 ... 1.7.0

Author SHA1 Message Date
Alireza Ahmadi
a078335d4c v1.7.0 2024-01-11 14:12:23 +01:00
Alireza Ahmadi
025545f0a4 small enhancements 2024-01-11 14:11:58 +01:00
Alireza Ahmadi
85c2d2ecd7 wireguard info page 2024-01-11 14:11:35 +01:00
Alireza Ahmadi
2026bd7546 update readme and pics 2024-01-11 01:51:39 +01:00
Alireza Ahmadi
f286080edd small fixes 2024-01-11 01:51:12 +01:00
Alireza Ahmadi
d36118fd95 [ui] user settings 2024-01-11 01:00:32 +01:00
shahin-io
1ee6e39bc3 Update EN & FA translation for WARP (#847)
* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml
2024-01-11 00:54:25 +01:00
shahin-io
d8e4f85e03 Small adjustment (#846)
* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update stream_ws.html

* Update stream_tcp.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.ru_RU.toml

* Update translate.vi_VN.toml

* Update translate.zh_Hans.toml

* Update translate.zh_Hans.toml

* Update translate.zh_Hans.toml

* Update translate.vi_VN.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml
2024-01-11 00:02:53 +01:00
Alireza Ahmadi
dd2ce332a6 [feature] WARP via wireguard 2024-01-11 00:01:27 +01:00
Alireza Ahmadi
41b0fe4af4 [ui] separate outbound and reverse 2024-01-11 00:00:35 +01:00
Ho3ein
c841c1f148 Minor changes (#844)
* set alpn h2 and https1 for tls

* VLESS as default

* if there is no security set to none

* better view for Allowed IPs wireguard outbound

* cpuCoreFormat

* matrix release + arm arch

s390x removed

* fix typo

* remove migrate_v2_ui

* bash - custom version

* fix translation

* update xray to 1.8.7

* auto gen + button for kcp & quic

* fix typo

* Centralized Xray URLs
2024-01-10 23:56:42 +01:00
Alireza Ahmadi
3b3d70aeaa [wg] auto generate keys 2024-01-10 02:16:43 +01:00
Alireza Ahmadi
2a311287bf fix translation 2024-01-10 02:16:17 +01:00
Alireza Ahmadi
dbb17f5829 [feature] wireguard inbound 2024-01-09 23:23:37 +01:00
Alireza Ahmadi
93412f8a21 fix shadowsocks inbound 2024-01-09 23:22:59 +01:00
Alireza Ahmadi
b63f305737 fix log writer crash 2024-01-09 23:22:44 +01:00
Alireza Ahmadi
2cd6305fe8 wireguard translations 2024-01-09 23:22:25 +01:00
Alireza Ahmadi
37b7c89d5e Merge pull request #842 from alireza0/dependabot/go_modules/github.com/xtls/xray-core-1.8.7
Bump github.com/xtls/xray-core from 1.8.6 to 1.8.7
2024-01-09 01:05:23 +01:00
shahin-io
df84b2fa46 Update README.md (#841)
* Update README.md

* Update README.md

* Update README.md
2024-01-09 01:05:05 +01:00
dependabot[bot]
d0a99a469b Bump github.com/xtls/xray-core from 1.8.6 to 1.8.7
Bumps [github.com/xtls/xray-core](https://github.com/xtls/xray-core) from 1.8.6 to 1.8.7.
- [Release notes](https://github.com/xtls/xray-core/releases)
- [Commits](https://github.com/xtls/xray-core/compare/v1.8.6...v1.8.7)

---
updated-dependencies:
- dependency-name: github.com/xtls/xray-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 22:00:53 +00:00
shahin-io
47792cdbd3 Small adjustment (#840)
* Update translate.en_US.toml

* Update outbound.html
2024-01-08 21:32:10 +01:00
Alireza Ahmadi
4df056f6a2 [outbound] update wireguard 2024-01-08 20:23:34 +01:00
shahin-io
94ac29ba7f Overall enhancement (#785)
* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update outbound.html

* Update tls_settings.html

* Update stream_tcp.html

* Update stream_ws.html

* Update vless.html

* Update trojan.html

* Update stream_sockopt.html

* Update stream_tcp.html

* Update stream_tcp.html

* Update stream_sockopt.html

* Update index.html

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.ru_RU.toml

* Update translate.vi_VN.toml

* Update translate.zh_Hans.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update outbound.html

* Update translate.en_US.toml

* Update translate.vi_VN.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.vi_VN.toml

* Update translate.ru_RU.toml

* Update translate.zh_Hans.toml

* Update client.html

* Update inbound.html

* Update translate.zh_Hans.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update client_bulk_modal.html

* Update client.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update client_bulk_modal.html

* Update client.html

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.ru_RU.toml

* Update translate.vi_VN.toml

* Update translate.zh_Hans.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update tls_settings.html

* Update outbound.html

* Update outbound.html

* Update trojan.html

* Update vless.html

* Update tls_settings.html

* Update index.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update outbound.html

* Update shadowsocks.html

* Update tls_settings.html

* Update tls_settings.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.ru_RU.toml

* Update translate.vi_VN.toml

* Update translate.zh_Hans.toml

* Update index.html

* Update index.html

* Update translate.vi_VN.toml

* Update translate.vi_VN.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update tls_settings.html

* Update translate.en_US.toml

* Update client_modal.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update inbound_info_modal.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update index.html

* Update index.html

* Update index.html

* Update index.html

* Update client_modal.html

* Update client_modal.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update client_bulk_modal.html

* Update client.html

* Update inbound.html

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.ru_RU.toml

* Update translate.vi_VN.toml

* Update translate.zh_Hans.toml

* Update client_bulk_modal.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update outbound.html

* Update stream_kcp.html

* Update stream_quic.html

* Update tls_settings.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update stream_sockopt.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update vless.html

* Update trojan.html

* Update client_bulk_modal.html

* Update client.html

* Update client_bulk_modal.html

* Update client.html

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.fa_IR.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml
2024-01-08 18:49:47 +01:00
Sudo Space
3a174144c4 Add wireguard to xray outbound (#763)
* Add wireguard to xray outbound

* [Fix little mistake] Add wireguard to xray outbound

* [Requested changes] Add wireguard to xray outbound

* Remove DNS field and add keepAlive field
2024-01-08 17:12:05 +01:00
Alireza Ahmadi
8b64976eef [bug] fix tcp http header version 2024-01-05 19:41:43 +01:00
Alireza Ahmadi
56336cbcef Merge pull request #825 from alireza0/dependabot/go_modules/github.com/shirou/gopsutil/v3-3.23.12
Bump github.com/shirou/gopsutil/v3 from 3.23.11 to 3.23.12
2024-01-05 02:42:14 +01:00
Alireza Ahmadi
43bc53a10e Merge pull request #826 from Enkidu-6/patch-1
Update README.md
2024-01-05 02:42:02 +01:00
Alireza Ahmadi
babe3e8788 fix switchEnable in filter mode #827 2024-01-05 02:40:43 +01:00
Enkidu
c247cd60b8 Update README.md 2024-01-02 01:58:53 -05:00
dependabot[bot]
06507f0e1f Bump github.com/shirou/gopsutil/v3 from 3.23.11 to 3.23.12
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.23.11 to 3.23.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.11...v3.23.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 21:13:55 +00:00
shahin-io
6a39ee037d Update README.md (#803)
I've updated it to reflect a more comprehensive set of features for the panel.
2023-12-31 17:05:13 +01:00
Alireza Ahmadi
96f9c73f5f Merge pull request #793 from shahin-io/patch-1
Update xray.html
2023-12-22 09:07:37 +01:00
Alireza Ahmadi
15f84de363 Merge pull request #798 from nonenty/main
fix: Unable to add routing rule that blocks bittorrent
2023-12-22 09:06:55 +01:00
Alireza Ahmadi
2d07b64839 fix protocol in routing rules modal #797 2023-12-22 09:05:07 +01:00
BizarraPan [Z+8]
1ef299951e Update xray_rule_modal.html
enable multiple select for rule.protocol
2023-12-22 14:42:27 +08:00
shahin-io
83fed835e1 Update xray.html
hello dear @alireza0 
 
As you may have noticed, the geo repository that manages Iran IPs has recently made changes to their traffic management rules. I’ve edited the file to reflect new changes.
2023-12-20 16:24:02 +00:00
Alireza Ahmadi
6e29022998 Merge pull request #790 from alireza0/dependabot/go_modules/google.golang.org/grpc-1.60.1
Bump google.golang.org/grpc from 1.60.0 to 1.60.1
2023-12-20 00:21:09 +01:00
dependabot[bot]
5e77dcb198 Bump google.golang.org/grpc from 1.60.0 to 1.60.1
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.60.0 to 1.60.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.60.0...v1.60.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-19 21:22:08 +00:00
Alireza Ahmadi
2d7607165b fix outbound socks/http #783 2023-12-19 14:59:49 +01:00
Alireza Ahmadi
c9e4918494 v1.6.4 2023-12-19 02:00:40 +01:00
Alireza Ahmadi
63b166ce40 fix filter view in inbounds 2023-12-19 01:06:29 +01:00
shahin-io
2ab1726131 unifying texts (#765)
* Update install.sh

* Update x-ui.sh

* Update install.sh

* Update stream_tcp.html

* Update stream_ws.html

* Update tls_settings.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.ru_RU.toml

* Update translate.zh_Hans.toml

* Update translate.vi_VN.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update dokodemo.html

* Update shadowsocks.html

* Update socks.html

* Update xray_rule_modal.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update dokodemo.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update index.html

* Update vless.html

* Update trojan.html

* Update outbound.html

* Update tls_settings.html

* Update dokodemo.html

* Update outbound.html

* Update stream_kcp.html

* Update outbound.html

* Update xray.html

* Update xray.html

* Update xray.html

* Update xray.html

* Update xray.html
2023-12-19 00:47:49 +01:00
Alireza Ahmadi
7dd5449cf4 [xray] add user field 2023-12-18 18:17:54 +01:00
Alireza Ahmadi
ded780b11a fix reverse edit/delete #766 2023-12-15 21:07:27 +01:00
shahin-io
2e44501573 fix small typo here and there (#761)
* Update install.sh

* Update x-ui.sh

* Update install.sh

* Update stream_tcp.html

* Update stream_ws.html

* Update tls_settings.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.fa_IR.toml

* Update translate.ru_RU.toml

* Update translate.zh_Hans.toml

* Update translate.vi_VN.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update dokodemo.html

* Update shadowsocks.html

* Update socks.html

* Update xray_rule_modal.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update dokodemo.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update index.html

* Update translate.en_US.toml

* Update translate.en_US.toml

* Update translate.en_US.toml
2023-12-14 22:36:32 +01:00
Alireza Ahmadi
3e7770ad97 Merge pull request #762 from MHSanaei/main
bug fix - lang
2023-12-14 22:32:53 +01:00
MHSanaei
0c380aebdd bug fix - lang 2023-12-14 10:23:47 +03:30
53 changed files with 2328 additions and 1181 deletions

View File

@@ -50,6 +50,6 @@ jobs:
with:
context: .
push: true
platforms: linux/amd64,linux/arm64/v8
platforms: linux/amd64,linux/arm64/v8, linux/arm/v7
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -1,4 +1,5 @@
name: Release X-ui
name: Release X-UI
on:
push:
tags:
@@ -6,127 +7,81 @@ on:
workflow_dispatch:
jobs:
linuxamd64build:
name: build x-ui amd64 version
build:
strategy:
matrix:
platform: [amd64, arm64, arm]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
- name: Checkout repository
uses: actions/checkout@v4.1.1
- name: Setup Go
uses: actions/setup-go@v5.0.0
with:
go-version: '1.21'
- name: build linux amd64 version
run: |
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o xui-release -v main.go
mkdir x-ui
cp xui-release x-ui/xui-release
cp x-ui.service x-ui/x-ui.service
cp x-ui.sh x-ui/x-ui.sh
cd x-ui
mv xui-release x-ui
mkdir bin
cd bin
wget https://github.com/XTLS/Xray-core/releases/download/v1.8.6/Xray-linux-64.zip
unzip Xray-linux-64.zip
rm -f Xray-linux-64.zip geoip.dat geosite.dat LICENSE README.md
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
wget -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
wget -O geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
mv xray xray-linux-amd64
cd ..
cd ..
- name: package
run: tar -zcvf x-ui-linux-amd64.tar.gz x-ui
- name: upload
uses: svenstaro/upload-release-action@2.7.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: x-ui-linux-amd64.tar.gz
asset_name: x-ui-linux-amd64.tar.gz
prerelease: true
linuxarm64build:
name: build x-ui arm64 version
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: build linux arm64 version
- name: Install dependencies for arm64 and arm
if: matrix.platform == 'arm64' || matrix.platform == 'arm'
run: |
sudo apt-get update
sudo apt install gcc-aarch64-linux-gnu
CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc go build -o xui-release -v main.go
mkdir x-ui
cp xui-release x-ui/xui-release
cp x-ui.service x-ui/x-ui.service
cp x-ui.sh x-ui/x-ui.sh
cd x-ui
mv xui-release x-ui
mkdir bin
cd bin
wget https://github.com/xtls/xray-core/releases/download/v1.8.6/Xray-linux-arm64-v8a.zip
unzip Xray-linux-arm64-v8a.zip
rm -f Xray-linux-arm64-v8a.zip geoip.dat geosite.dat LICENSE README.md
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
wget -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
wget -O geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
mv xray xray-linux-arm64
cd ..
cd ..
- name: package
run: tar -zcvf x-ui-linux-arm64.tar.gz x-ui
- name: upload
uses: svenstaro/upload-release-action@2.7.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: x-ui-linux-arm64.tar.gz
asset_name: x-ui-linux-arm64.tar.gz
prerelease: true
linuxs390xbuild:
name: build x-ui s390x version
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: build linux s390x version
if [ "${{ matrix.platform }}" == "arm" ]; then
sudo apt install gcc-arm-linux-gnueabihf
fi
- name: Build x-ui
run: |
sudo apt-get update
sudo apt install gcc-s390x-linux-gnu -y
CGO_ENABLED=1 GOOS=linux GOARCH=s390x CC=s390x-linux-gnu-gcc go build -o xui-release -v main.go
export CGO_ENABLED=1
export GOOS=linux
export GOARCH=${{ matrix.platform }}
if [ "${{ matrix.platform }}" == "arm64" ]; then
export CC=aarch64-linux-gnu-gcc
elif [ "${{ matrix.platform }}" == "arm" ]; then
export CC=arm-linux-gnueabihf-gcc
fi
go build -o xui-release -v main.go
mkdir x-ui
cp xui-release x-ui/xui-release
cp x-ui.service x-ui/x-ui.service
cp x-ui.sh x-ui/x-ui.sh
cd x-ui
mv xui-release x-ui
mkdir bin
cd bin
wget https://github.com/xtls/xray-core/releases/download/v1.8.6/Xray-linux-s390x.zip
unzip Xray-linux-s390x.zip
rm -f Xray-linux-s390x.zip geoip.dat geosite.dat LICENSE README.md
cp xui-release x-ui/
cp x-ui.service x-ui/
cp x-ui.sh x-ui/
mv x-ui/xui-release x-ui/x-ui
mkdir x-ui/bin
cd x-ui/bin
# Download dependencies
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v1.8.7/"
if [ "${{ matrix.platform }}" == "amd64" ]; then
wget ${Xray_URL}Xray-linux-64.zip
unzip Xray-linux-64.zip
rm -f Xray-linux-64.zip
elif [ "${{ matrix.platform }}" == "arm64" ]; then
wget ${Xray_URL}Xray-linux-arm64-v8a.zip
unzip Xray-linux-arm64-v8a.zip
rm -f Xray-linux-arm64-v8a.zip
else
wget ${Xray_URL}Xray-linux-arm32-v7a.zip
unzip Xray-linux-arm32-v7a.zip
rm -f Xray-linux-arm32-v7a.zip
fi
rm -f geoip.dat geosite.dat geoip_IR.dat geosite_IR.dat
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
wget https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
wget -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
wget -O geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
mv xray xray-linux-s390x
cd ..
cd ..
- name: package
run: tar -zcvf x-ui-linux-s390x.tar.gz x-ui
- name: upload
mv xray xray-linux-${{ matrix.platform }}
cd ../..
- name: Package
run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
- name: Upload
uses: svenstaro/upload-release-action@2.7.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: x-ui-linux-s390x.tar.gz
asset_name: x-ui-linux-s390x.tar.gz
file: x-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
prerelease: true
overwrite: true

View File

@@ -1,17 +1,25 @@
#!/bin/sh
if [ $1 == "amd64" ]; then
ARCH="64";
FNAME="amd64";
elif [ $1 == "arm64" ]; then
ARCH="arm64-v8a"
FNAME="arm64";
else
ARCH="64";
FNAME="amd64";
fi
case $1 in
amd64)
ARCH="64"
FNAME="amd64"
;;
armv8 | arm64 | aarch64)
ARCH="arm64-v8a"
FNAME="arm64"
;;
armv7 | arm | arm32)
ARCH="arm32-v7a"
FNAME="arm32"
;;
*)
ARCH="64"
FNAME="amd64"
;;
esac
mkdir -p build/bin
cd build/bin
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.6/Xray-linux-${ARCH}.zip"
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.7/Xray-linux-${ARCH}.zip"
unzip "Xray-linux-${ARCH}.zip"
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat LICENSE README.md
mv xray "xray-linux-${FNAME}"

230
README.md
View File

@@ -1,5 +1,5 @@
# X-UI
**Advanced GUI panel based on Xray Core supports multiple protocols and languages**
**An Advanced Web Panel • Built on Xray Core**
![](https://img.shields.io/github/v/release/alireza0/x-ui.svg)
![](https://img.shields.io/docker/pulls/alireza7/x-ui.svg)
@@ -7,32 +7,30 @@
[![Downloads](https://img.shields.io/github/downloads/alireza0/x-ui/total.svg)](https://img.shields.io/github/downloads/alireza0/x-ui/total.svg)
[![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](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
**If you think this project is helpful to you, you may wish to give a**:star2:
**If you think this project is helpful to you, you may wish to give a** :star2:
<img width="125" alt="image"
src="https://github.com/alireza0/x-ui/assets/115543613/dd4f10dd-8bb0-40cf-846f-1fe1de7a6275">
**Buy Me a Coffee :**
- USDT Tron (TRC20): `TYTq73Gj6dJ67qe58JVPD9zpjW2cc9XgVz`
- USDT (TRC20): `TYTq73Gj6dJ67qe58JVPD9zpjW2cc9XgVz`
- Tezos (XTZ):
`tz2Wnh2SsY1eezXrcLChu6idWpgdHzUFQcts`
## Quick Look
## Quick Overview
| Features | Enable? |
| -------------------------------------- | :----------------: |
| Multi-Protocol | :heavy_check_mark: |
| Multi-Language | :heavy_check_mark: |
| Multi-User Inbounds | :heavy_check_mark: |
| Advanced Traffic Routing | :heavy_check_mark: |
| Multi-Client/Inbound | :heavy_check_mark: |
| Advanced Traffic Routing Interface | :heavy_check_mark: |
| Client & Traffic & System Status | :heavy_check_mark: |
| Date & Traffic Cap Based on First Use | :heavy_check_mark: |
| REST API | :heavy_check_mark: |
|Show Online Users | :heavy_check_mark: |
| Manage Users Traffic Data & Expiry Date| :heavy_check_mark: |
| Apply Expiry Date based on First Usage | :heavy_check_mark: |
| Telegram Bot (admin + clients) | :heavy_check_mark: |
| Database Backup using Telegram Bot | :heavy_check_mark: |
| Subscription Link + UserInfo | :heavy_check_mark: |
| TG Bot (DB backup + admin + client) | :heavy_check_mark: |
| Subscription Service (link + info) | :heavy_check_mark: |
| Search in Deep | :heavy_check_mark: |
| Dark/Light Theme | :heavy_check_mark: |
@@ -45,18 +43,24 @@ bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.s
## Install Custom Version
To install your desired version you can add the version to the end of install command. Example for ver `0.5.2`:
**Step 1:** To install your desired version, add the version to the end of the installation command. e.g., ver `1.6.4`:
```sh
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh) 0.5.2
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh) 1.6.4
```
## Manual Install & Upgrade
1. First download the latest compressed package from https://github.com/alireza0/x-ui/releases, generally choose Architecture `amd64`
2. Then upload the compressed package to the server's `/root/` directory and login to the server with user `root`
<details>
<summary>Click for details</summary>
### Usage
> If your server cpu architecture is not `amd64` replace another architecture
**Step 1:** First download the latest compressed package from https://github.com/alireza0/x-ui/releases, generally choose Architecture `amd64`
**Step 2:** Then upload the compressed package to the server's `/root/` directory and login to the server with user `root`
> If your server CPU architecture is not `amd64` replace it with the appropriate architecture
```sh
ARCH=$(uname -m)
@@ -73,15 +77,22 @@ systemctl enable x-ui
systemctl restart x-ui
```
## Install Using Docker
</details>
1. Install Docker
## Install using Docker
<details>
<summary>Click for details</summary>
### Usage
**Step 1:** Install Docker
```shell
curl -fsSL https://get.docker.com | sh
```
2. Install X-UI
**Step 2:** Install X-UI
```shell
mkdir x-ui && cd x-ui
@@ -100,6 +111,8 @@ docker run -itd \
docker build -t x-ui .
```
</details>
## Languages
- English
@@ -110,22 +123,21 @@ docker build -t x-ui .
## Features
- Supported protocols: VMess, VLESS, Trojan, Shadowsocks, Dokodemo-door, SOCKS, HTTP
- Support XTLS native encryptions (Vision, REALITY)
- Support advanced JSON editor GUI for Xray-Core configuration
- Support advanced GUI for routing traffic (Reverse and Transparent proxy, Multi-Domain, Multi-Certificate, Multi-Port per inbound)
- Support Multi-User per inbound
- Support applying traffic data limits and expiry dates per user/inbound
- Support system status monitoring
- Support deep database search
- Show traffic statistics
- Show online users
- Show users with expired date or exceeded traffic limits
- Support subscription (multi) link
- Support import/export database
- Support One-Click SSL certificate application and automatic renewal
- Support HTTPS for panel (self-provided domain name + SSL certificate)
- Support Dark/Light theme UI
- Supports protocols including VLESS, VMess, Trojan, Shadowsocks, Dokodemo-door, SOCKS, HTTP, Wireguard
- Supports XTLS protocols, including Vision and REALITY
- An advanced interface for routing traffic, incorporating PROXY Protocol, Reverse, External, and Transparent Proxy, along with Multi-Domain, SSL Certificate, and Port
- Support auto generate Cloudflare WARP using Wireguard outbound
- An interactive JSON interface for Xray template configuration
- An advanced interface for inbound and outbound configuration
- Clients traffic cap and expiration date based on first use
- Displays online clients, traffic statistics, and system status monitoring
- Deep database search
- Displays depleted clients with expired dates or exceeded traffic cap
- Subscription service with (multi)link
- Importing and exporting databases
- One-Click SSL certificate application and automatic renewal
- HTTPS for secure access to the web panel and subscription service (self-provided domain + SSL certificate)
- Dark/Light theme
## Recommended OS
@@ -134,12 +146,13 @@ docker build -t x-ui .
- Debian 10+
- Fedora 36+
## Screenshots
## Preview
![inbounds](./media/inbounds.png)
![Dark inbounds](./media/inbounds-dark.png)
![outbounds](./media/outbounds.png)
![rules](./media/rules.png)
![warp](./media/warp.png)
## API Routes
@@ -199,6 +212,17 @@ docker build -t x-ui .
<details>
<summary>Click for details</summary>
### Cloudflare
The admin management script has a built-in SSL certificate application for Cloudflare. To use this script to apply for a certificate, you need the following:
- Cloudflare registered email
- Cloudflare Global API Key
- The domain name has been resolved to the current server through cloudflare
**Step 1:** Run the`x-ui`command on the server's terminal and then choose `17`. Then enter the information as requested.
### Certbot
```bash
@@ -218,40 +242,42 @@ certbot certonly --standalone --register-unsafely-without-email --non-interactiv
### Usage
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:
The web panel supports daily traffic, panel login, database backup, system status, client info, and other notification and functions through the Telegram Bot. To use the bot, you need to set the bot-related parameters in the panel, 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
- Telegram Token
- Admin Chat ID(s)
- Notification Time (in cron syntax)
- Database Backup
- CPU Load Threshold Notification
**Crontab Time Format**
Reference syntax:
- 30 \* \* \* \* \* //Notify at the 30s of each point
- 0 \*/10 \* \* \* \* //Notify at the first second of each 10 minutes
- @hourly // hourly notification
- @daily // Daily notification (00:00 in the morning)
- @every 8h // notify every 8 hours
- `*/30 * * * *` - Notify every 30 minutes, every hour
- `30 * * * * *` - Notify at the 30th second of each minute
- `0 */10 * * * *` - Notify at the start of every 10 minutes
- `@hourly` - Hourly notification
- `@daily` - Daily notification (00:00 AM)
- `@every 8h` - Notify every 8 hours
For more info about [Crontab](https://acquia.my.site.com/s/article/360004224494-Cron-time-string-format)
### Features
- Report periodic
- Login notification
- CPU threshold notification
- Threshold for Expiration time and Traffic to report in advance
- Support client report menu if client's telegram ID or telegram UserName added to the user's configurations
- Support telegram traffic report searched with UUID (VMESS/VLESS) or Password (TROJAN) - anonymously
- Menu based bot
- Search client by email ( only admin )
- Check all inbounds
- Check server status
- Check depleted users
- Receive backup by request and in periodic reports
- Multi language bot
- Periodic reporting
- Login notifications
- CPU load threshold notifications
- Advance notifications for expiration time and traffic
- Client reporting menu with Telegram ID or username in configurations
- Anonymous traffic reports, search by UUID (VLESS/VMess) or Password (Trojan/Shadowsocks)
- Menu-based bot
- Client search by email (admin only)
- Inbound checks
- System status check
- Depleted client checks
- Backup on request and in periodic reports
- Multilingual support
</details>
## Troubleshoots
@@ -261,50 +287,58 @@ Reference syntax:
### Enable Traffic Usage
Please be aware if you upgrade from an old X-UI version or other forks, by default data traffic usage for users may not work! it's recommended to follow below steps for enabeling:
If you are upgrading from an older version or other forks and find that data traffic usage for clients may not work by default, follow the steps below to enable it:
1. Find this section in config file
**Step 1: Locate the Configuration Section**
```json
"policy": {
"system": {
```
2. Add below section just after ` "policy": {` :
```json
"levels": {
"0": {
"statsUserUplink": true,
"statsUserDownlink": true
}
},
```
- The final output is like:
Find the following section in the config file:
```json
"policy": {
"levels": {
"0": {
"statsUserUplink": true,
"statsUserDownlink": true
}
},
"system": {
"statsInboundDownlink": true,
"statsInboundUplink": true
// Other policy configurations
}
},
"routing": {
```
**Step 2: Add the Required Configuration**
3. Save and restart panel
Add the following section just after `"policy": {`:
```json
"levels": {
"0": {
"statsUserUplink": true,
"statsUserDownlink": true
}
},
```
**Step 3: Final Configuration**
Your final config should look like this:
```json
"policy": {
"levels": {
"0": {
"statsUserUplink": true,
"statsUserDownlink": true
}
},
"system": {
"statsInboundDownlink": true,
"statsInboundUplink": true
}
},
"routing": {
// Other routing configurations
},
```
**Step 4: Save and Restart**
Save your changes and restart the Xray Service
</details>
## a Special Thanks to
## A Special Thanks to
- [HexaSoftwareTech](https://github.com/HexaSoftwareTech/)
- [MHSanaei](https://github.com/MHSanaei)

View File

@@ -1 +1 @@
1.6.3
1.7.0

45
go.mod
View File

@@ -11,11 +11,11 @@ require (
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pelletier/go-toml/v2 v2.1.1
github.com/robfig/cron/v3 v3.0.1
github.com/shirou/gopsutil/v3 v3.23.11
github.com/xtls/xray-core v1.8.6
github.com/shirou/gopsutil/v3 v3.23.12
github.com/xtls/xray-core v1.8.7
go.uber.org/atomic v1.11.0
golang.org/x/text v0.14.0
google.golang.org/grpc v1.60.0
google.golang.org/grpc v1.60.1
gorm.io/driver/sqlite v1.5.4
gorm.io/gorm v1.25.5
)
@@ -24,11 +24,10 @@ require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cloudflare/circl v1.3.6 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect
github.com/gin-contrib/gzip v0.0.6
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
@@ -38,7 +37,7 @@ require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
@@ -46,7 +45,7 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
@@ -54,15 +53,15 @@ require (
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.13.1 // indirect
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
github.com/pires/go-proxyproto v0.7.0 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/quic-go/quic-go v0.40.0 // indirect
github.com/refraction-networking/utls v1.5.4 // indirect
github.com/quic-go/quic-go v0.40.1 // indirect
github.com/refraction-networking/utls v1.6.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/sagernet/sing v0.2.17 // indirect
github.com/sagernet/sing-shadowsocks v0.2.5 // indirect
github.com/sagernet/sing v0.3.0 // indirect
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
@@ -74,20 +73,20 @@ require (
github.com/vishvananda/netns v0.0.4 // indirect
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.uber.org/mock v0.3.0 // indirect
go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect
go.uber.org/mock v0.4.0 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/time v0.4.0 // indirect
golang.org/x/tools v0.15.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.16.1 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/protobuf v1.31.0 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect
lukechampine.com/blake3 v1.2.1 // indirect

93
go.sum
View File

@@ -27,8 +27,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg=
github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -44,8 +44,6 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
@@ -116,8 +114,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8=
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -145,8 +143,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -191,8 +189,8 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nicksnyder/go-i18n/v2 v2.3.0 h1:2NPsCsNFCVd7i+Su0xYsBrIhS3bE2XMv5gNTft2O+PQ=
github.com/nicksnyder/go-i18n/v2 v2.3.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU=
github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
@@ -220,10 +218,10 @@ github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/refraction-networking/utls v1.5.4 h1:9k6EO2b8TaOGsQ7Pl7p9w6PUhx18/ZCeT0WNTZ7Uw4o=
github.com/refraction-networking/utls v1.5.4/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/refraction-networking/utls v1.6.0 h1:X5vQMqVx7dY7ehxxqkFER/W6DSjy8TMqSItXm8hRDYQ=
github.com/refraction-networking/utls v1.6.0/go.mod h1:kHJ6R9DFFA0WsRgBM35iiDku4O7AqPR6y79iuzW7b10=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
@@ -232,15 +230,15 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI=
github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY=
github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A=
github.com/sagernet/sing v0.3.0 h1:PIDVFZHnQAAYRL1UYqNM+0k5s8f/tb1lUW6UDcQiOc8=
github.com/sagernet/sing v0.3.0/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ=
github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@@ -307,18 +305,18 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 h1:capMfFYRgH9BCLd6A3Er/cH3A9Nz3CU2KwxwOQZIePI=
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
github.com/xtls/xray-core v1.8.6 h1:tr3nk/fZnFfCsmgZv7B3RC72N5qUC88oMGVLlybDey8=
github.com/xtls/xray-core v1.8.6/go.mod h1:hj2EB8rtcLdlTC8zxiWm5xL+C0k2Aie9Pk0mXtDEP6U=
github.com/xtls/xray-core v1.8.7 h1:lb8O1l3/eAg3YAXA6tLm5M6N7BsX8wxW9sJLjU3dHkA=
github.com/xtls/xray-core v1.8.7/go.mod h1:9rFpflfQbgFeH1VKJw7yUmEy7myOyDCgNXXl0bmmyOo=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ=
go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -328,11 +326,11 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -348,8 +346,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -359,8 +357,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -380,8 +378,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -392,20 +391,20 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb h1:c5tyN8sSp8jSDxdCCDXVOpJwYXXhmTkNMt+g0zTSOic=
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
@@ -418,19 +417,19 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k=
google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

View File

@@ -23,25 +23,15 @@ else
fi
echo "The OS release is: $release"
arch=$(arch)
if [[ $arch == "x86_64" || $arch == "x64" || $arch == "amd64" ]]; then
arch="amd64"
elif [[ $arch == "aarch64" || $arch == "arm64" ]]; then
arch="arm64"
elif [[ $arch == "s390x" ]]; then
arch="s390x"
else
arch="amd64"
echo -e "${red} Failed to check system arch, will use default arch: ${arch}${plain}"
fi
echo "arch: ${arch}"
if [ $(getconf WORD_BIT) != '32' ] && [ $(getconf LONG_BIT) != '64' ]; then
echo "x-ui dosen't support 32-bit(x86) system, please use 64 bit operating system(x86_64) instead, if there is something wrong, please get in touch with me!"
exit -1
fi
arch() {
case "$(uname -m)" in
x86_64 | x64 | amd64) echo 'amd64' ;;
armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
armv7* | armv7 | arm | arm32 ) echo 'arm' ;;
*) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
esac
}
echo "arch: $(arch)"
os_version=""
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
@@ -122,18 +112,18 @@ install_x-ui() {
exit 1
fi
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/alireza0/x-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/alireza0/x-ui/releases/download/${last_version}/x-ui-linux-$(arch).tar.gz
if [[ $? -ne 0 ]]; then
echo -e "${red}Dowanloading 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
fi
else
last_version=$1
url="https://github.com/alireza0/x-ui/releases/download/${last_version}/x-ui-linux-${arch}.tar.gz"
echo -e "Begining to install x-ui v$1"
wget -N --no-check-certificate -O /usr/local/x-ui-linux-${arch}.tar.gz ${url}
url="https://github.com/alireza0/x-ui/releases/download/${last_version}/x-ui-linux-$(arch).tar.gz"
echo -e "Beginning to install x-ui v$1"
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch).tar.gz ${url}
if [[ $? -ne 0 ]]; then
echo -e "${red}dowanload x-ui v$1 failed,please check the verison exists${plain}"
echo -e "${red}download x-ui v$1 failed,please check the version exists${plain}"
exit 1
fi
fi
@@ -143,10 +133,10 @@ install_x-ui() {
rm /usr/local/x-ui/ -rf
fi
tar zxvf x-ui-linux-${arch}.tar.gz
rm x-ui-linux-${arch}.tar.gz -f
tar zxvf x-ui-linux-$(arch).tar.gz
rm x-ui-linux-$(arch).tar.gz -f
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/
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/alireza0/x-ui/main/x-ui.sh
chmod +x /usr/local/x-ui/x-ui.sh
@@ -181,6 +171,6 @@ install_x-ui() {
echo "------------------------------------------"
}
echo -e "${green}Excuting...${plain}"
echo -e "${green}Running...${plain}"
install_base
install_x-ui $1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 96 KiB

BIN
media/warp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -408,6 +408,10 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
}
}
if security != "tls" && security != "reality" {
params["security"] = "none"
}
externalProxies, _ := stream["externalProxy"].([]interface{})
if len(externalProxies) > 0 {
@@ -581,6 +585,10 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
}
}
if security != "tls" && security != "reality" {
params["security"] = "none"
}
externalProxies, _ := stream["externalProxy"].([]interface{})
if len(externalProxies) > 0 {

View File

@@ -56,6 +56,10 @@ class DBInbound {
return this.protocol === Protocols.HTTP;
}
get isWireguard() {
return this.protocol === Protocols.WIREGUARD;
}
get address() {
let address = location.hostname;
if (!ObjectUtil.isEmpty(this.listen) && this.listen !== "0.0.0.0") {

View File

@@ -8,6 +8,7 @@ const Protocols = {
Shadowsocks: "shadowsocks",
Socks: "socks",
HTTP: "http",
Wireguard: "wireguard"
};
const SSMethods = {
@@ -46,18 +47,27 @@ const ALPN_OPTION = {
HTTP1: "http/1.1",
};
const outboundDomainStrategies = [
const OutboundDomainStrategies = [
"AsIs",
"UseIP",
"UseIPv4",
"UseIPv6"
]
];
const WireguardDomainStrategy = [
"ForceIP",
"ForceIPv4",
"ForceIPv4v6",
"ForceIPv6",
"ForceIPv6v4"
];
Object.freeze(Protocols);
Object.freeze(SSMethods);
Object.freeze(TLS_FLOW_CONTROL);
Object.freeze(ALPN_OPTION);
Object.freeze(outboundDomainStrategies);
Object.freeze(OutboundDomainStrategies);
Object.freeze(WireguardDomainStrategy);
class CommonClass {
@@ -625,6 +635,7 @@ Outbound.Settings = class extends CommonClass {
case Protocols.Shadowsocks: return new Outbound.ShadowsocksSettings();
case Protocols.Socks: return new Outbound.SocksSettings();
case Protocols.HTTP: return new Outbound.HttpSettings();
case Protocols.Wireguard: return new Outbound.WireguardSettings();
default: return null;
}
}
@@ -640,6 +651,7 @@ Outbound.Settings = class extends CommonClass {
case Protocols.Shadowsocks: return Outbound.ShadowsocksSettings.fromJson(json);
case Protocols.Socks: return Outbound.SocksSettings.fromJson(json);
case Protocols.HTTP: return Outbound.HttpSettings.fromJson(json);
case Protocols.Wireguard: return Outbound.WireguardSettings.fromJson(json);
default: return null;
}
}
@@ -839,12 +851,12 @@ Outbound.ShadowsocksSettings = class extends CommonClass {
}
};
Outbound.SocksSettings = class extends CommonClass {
constructor(address, port, user, password) {
constructor(address, port, user, pass) {
super();
this.address = address;
this.port = port;
this.user = user;
this.password = password;
this.pass = pass;
}
static fromJson(json={}) {
@@ -854,7 +866,7 @@ Outbound.SocksSettings = class extends CommonClass {
servers[0].address,
servers[0].port,
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
ObjectUtil.isArrEmpty(servers[0].password) ? '' : servers[0].users[0].password,
ObjectUtil.isArrEmpty(servers[0].pass) ? '' : servers[0].users[0].pass,
);
}
@@ -863,18 +875,18 @@ Outbound.SocksSettings = class extends CommonClass {
servers: [{
address: this.address,
port: this.port,
users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, password: this.password}],
users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, pass: this.pass}],
}],
};
}
};
Outbound.HttpSettings = class extends CommonClass {
constructor(address, port, user, password) {
constructor(address, port, user, pass) {
super();
this.address = address;
this.port = port;
this.user = user;
this.password = password;
this.pass = pass;
}
static fromJson(json={}) {
@@ -884,7 +896,7 @@ Outbound.HttpSettings = class extends CommonClass {
servers[0].address,
servers[0].port,
ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
ObjectUtil.isArrEmpty(servers[0].password) ? '' : servers[0].users[0].password,
ObjectUtil.isArrEmpty(servers[0].pass) ? '' : servers[0].users[0].pass,
);
}
@@ -893,8 +905,89 @@ Outbound.HttpSettings = class extends CommonClass {
servers: [{
address: this.address,
port: this.port,
users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, password: this.password}],
users: ObjectUtil.isEmpty(this.user) ? [] : [{user: this.user, pass: this.pass}],
}],
};
}
};
Outbound.WireguardSettings = class extends CommonClass {
constructor(
mtu=1420, secretKey=Wireguard.generateKeypair().privateKey,
address='', workers=2, domainStrategy='', reserved='',
peers=[new Outbound.WireguardSettings.Peer()], kernelMode=false) {
super();
this.mtu = mtu;
this.secretKey = secretKey;
this.pubKey = secretKey.length>0 ? Wireguard.generateKeypair(secretKey).publicKey : '';
this.address = address instanceof Array ? address.join(',') : address;
this.workers = workers;
this.domainStrategy = domainStrategy;
this.reserved = reserved instanceof Array ? reserved.join(',') : reserved;
this.peers = peers;
this.kernelMode = kernelMode;
}
addPeer() {
this.peers.push(new Outbound.WireguardSettings.Peer());
}
delPeer(index) {
this.peers.splice(index, 1);
}
static fromJson(json={}){
return new Outbound.WireguardSettings(
json.mtu,
json.secretKey,
json.address,
json.workers,
json.domainStrategy,
json.reserved,
json.peers.map(peer => Outbound.WireguardSettings.Peer.fromJson(peer)),
json.kernelMode,
);
}
toJson() {
return {
mtu: this.mtu?? undefined,
secretKey: this.secretKey,
address: this.address ? this.address.split(",") : [],
workers: this.workers?? undefined,
domainStrategy: WireguardDomainStrategy.includes(this.domainStrategy) ? this.domainStrategy : undefined,
reserved: this.reserved ? this.reserved.split(",") : undefined,
peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers),
kernelMode: this.kernelMode,
};
}
};
Outbound.WireguardSettings.Peer = class extends CommonClass {
constructor(publicKey='', psk='', allowedIPs=['0.0.0.0/0','::/0'], endpoint='', keepAlive=0) {
super();
this.publicKey = publicKey;
this.psk = psk;
this.allowedIPs = allowedIPs;
this.endpoint = endpoint;
this.keepAlive = keepAlive;
}
static fromJson(json={}){
return new Outbound.WireguardSettings.Peer(
json.publicKey,
json.preSharedKey,
json.allowedIPs,
json.endpoint,
json.keepAlive
);
}
toJson() {
return {
publicKey: this.publicKey,
preSharedKey: this.psk.length>0 ? this.psk : undefined,
allowedIPs: this.allowedIPs ? this.allowedIPs : undefined,
endpoint: this.endpoint,
keepAlive: this.keepAlive?? undefined,
};
}
};

View File

@@ -6,6 +6,7 @@ const Protocols = {
DOKODEMO: 'dokodemo-door',
SOCKS: 'socks',
HTTP: 'http',
WIREGUARD: 'wireguard',
};
const SSMethods = {
@@ -229,6 +230,7 @@ TcpStreamSettings.TcpRequest = class extends XrayCommonClass {
toJson() {
return {
version: this.version,
method: this.method,
path: ObjectUtil.clone(this.path),
headers: XrayCommonClass.toV2Headers(this.headers),
@@ -406,7 +408,7 @@ class HttpStreamSettings extends XrayCommonClass {
class QuicStreamSettings extends XrayCommonClass {
constructor(security='none',
key='', type='none') {
key=RandomUtil.randomSeq(10), type='none') {
super();
this.security = security;
this.key = key;
@@ -458,7 +460,7 @@ class TlsStreamSettings extends XrayCommonClass {
cipherSuites = '',
rejectUnknownSni = false,
certificates=[new TlsStreamSettings.Cert()],
alpn=[],
alpn=[ALPN_OPTION.H2,ALPN_OPTION.HTTP1],
settings=new TlsStreamSettings.Settings()) {
super();
this.sni = serverName;
@@ -812,7 +814,7 @@ class Sniffing extends XrayCommonClass {
class Inbound extends XrayCommonClass {
constructor(port=RandomUtil.randomIntRange(10000, 60000),
listen='',
protocol=Protocols.VMESS,
protocol=Protocols.VLESS,
settings=null,
streamSettings=new StreamSettings(),
tag='',
@@ -1138,7 +1140,7 @@ class Inbound extends XrayCommonClass {
}
}
if (security === 'reality') {
else if (security === 'reality') {
params.set("security", "reality");
params.set("pbk", this.stream.reality.settings.publicKey);
params.set("fp", this.stream.reality.settings.fingerprint);
@@ -1156,6 +1158,10 @@ class Inbound extends XrayCommonClass {
}
}
else {
params.set("security", "none");
}
const link = `vless://${uuid}@${address}:${port}`;
const url = new URL(link);
for (const [key, value] of params) {
@@ -1314,7 +1320,7 @@ class Inbound extends XrayCommonClass {
}
}
if (security === 'reality') {
else if (security === 'reality') {
params.set("security", "reality");
params.set("pbk", this.stream.reality.settings.publicKey);
params.set("fp", this.stream.reality.settings.fingerprint);
@@ -1328,6 +1334,9 @@ class Inbound extends XrayCommonClass {
params.set("spx", this.stream.reality.settings.spiderX);
}
}
else {
params.set("security", "none");
}
const link = `trojan://${clientPassword}@${address}:${port}`;
const url = new URL(link);
@@ -1444,6 +1453,7 @@ Inbound.Settings = class extends XrayCommonClass {
case Protocols.DOKODEMO: return new Inbound.DokodemoSettings(protocol);
case Protocols.SOCKS: return new Inbound.SocksSettings(protocol);
case Protocols.HTTP: return new Inbound.HttpSettings(protocol);
case Protocols.WIREGUARD: return new Inbound.WireguardSettings(protocol);
default: return null;
}
}
@@ -1457,6 +1467,7 @@ Inbound.Settings = class extends XrayCommonClass {
case Protocols.DOKODEMO: return Inbound.DokodemoSettings.fromJson(json);
case Protocols.SOCKS: return Inbound.SocksSettings.fromJson(json);
case Protocols.HTTP: return Inbound.HttpSettings.fromJson(json);
case Protocols.WIREGUARD: return Inbound.WireguardSettings.fromJson(json);
default: return null;
}
}
@@ -2047,3 +2058,69 @@ Inbound.HttpSettings.HttpAccount = class extends XrayCommonClass {
return new Inbound.HttpSettings.HttpAccount(json.user, json.pass);
}
};
Inbound.WireguardSettings = class extends XrayCommonClass {
constructor(protocol, mtu=1420, secretKey=Wireguard.generateKeypair().privateKey, peers=[new Inbound.WireguardSettings.Peer()], kernelMode=false) {
super(protocol);
this.mtu = mtu;
this.secretKey = secretKey;
this.pubKey = secretKey.length>0 ? Wireguard.generateKeypair(secretKey).publicKey : '';
this.peers = peers;
this.kernelMode = kernelMode;
}
addPeer() {
this.peers.push(new Inbound.WireguardSettings.Peer());
}
delPeer(index) {
this.peers.splice(index, 1);
}
static fromJson(json={}){
return new Inbound.WireguardSettings(
Protocols.WIREGUARD,
json.mtu,
json.secretKey,
json.peers.map(peer => Inbound.WireguardSettings.Peer.fromJson(peer)),
json.kernelMode,
);
}
toJson() {
return {
mtu: this.mtu?? undefined,
secretKey: this.secretKey,
peers: Inbound.WireguardSettings.Peer.toJsonArray(this.peers),
kernelMode: this.kernelMode,
};
}
};
Inbound.WireguardSettings.Peer = class extends XrayCommonClass {
constructor(publicKey='', psk='', allowedIPs=['0.0.0.0/0','::/0'], keepAlive=0) {
super();
this.publicKey = publicKey;
this.psk = psk;
this.allowedIPs = allowedIPs;
this.keepAlive = keepAlive;
}
static fromJson(json={}){
return new Inbound.WireguardSettings.Peer(
json.publicKey,
json.preSharedKey,
json.allowedIPs,
json.keepAlive
);
}
toJson() {
return {
publicKey: this.publicKey,
preSharedKey: this.psk.length>0 ? this.psk : undefined,
allowedIPs: this.allowedIPs,
keepAlive: this.keepAlive?? undefined,
};
}
};

View File

@@ -20,6 +20,14 @@ function sizeFormat(size) {
}
}
function cpuCoreFormat(cores) {
if (cores === 1) {
return "1 Core";
} else {
return cores + " Cores";
}
}
function base64(str) {
return Base64.encode(str);
}

View File

@@ -296,3 +296,190 @@ class ObjectUtil {
return true;
}
}
class Wireguard {
static gf(init) {
var r = new Float64Array(16);
if (init) {
for (var i = 0; i < init.length; ++i)
r[i] = init[i];
}
return r;
}
static pack(o, n) {
var b, m = this.gf(), t = this.gf();
for (var i = 0; i < 16; ++i)
t[i] = n[i];
this.carry(t);
this.carry(t);
this.carry(t);
for (var j = 0; j < 2; ++j) {
m[0] = t[0] - 0xffed;
for (var i = 1; i < 15; ++i) {
m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
this.cswap(t, m, 1 - b);
}
for (var i = 0; i < 16; ++i) {
o[2 * i] = t[i] & 0xff;
o[2 * i + 1] = t[i] >> 8;
}
}
static carry(o) {
var c;
for (var i = 0; i < 16; ++i) {
o[(i + 1) % 16] += (i < 15 ? 1 : 38) * Math.floor(o[i] / 65536);
o[i] &= 0xffff;
}
}
static cswap(p, q, b) {
var t, c = ~(b - 1);
for (var i = 0; i < 16; ++i) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
}
static add(o, a, b) {
for (var i = 0; i < 16; ++i)
o[i] = (a[i] + b[i]) | 0;
}
static subtract(o, a, b) {
for (var i = 0; i < 16; ++i)
o[i] = (a[i] - b[i]) | 0;
}
static multmod(o, a, b) {
var t = new Float64Array(31);
for (var i = 0; i < 16; ++i) {
for (var j = 0; j < 16; ++j)
t[i + j] += a[i] * b[j];
}
for (var i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
for (var i = 0; i < 16; ++i)
o[i] = t[i];
this.carry(o);
this.carry(o);
}
static invert(o, i) {
var c = this.gf();
for (var a = 0; a < 16; ++a)
c[a] = i[a];
for (var a = 253; a >= 0; --a) {
this.multmod(c, c, c);
if (a !== 2 && a !== 4)
this.multmod(c, c, i);
}
for (var a = 0; a < 16; ++a)
o[a] = c[a];
}
static clamp(z) {
z[31] = (z[31] & 127) | 64;
z[0] &= 248;
}
static generatePublicKey(privateKey) {
var r, z = new Uint8Array(32);
var a = this.gf([1]),
b = this.gf([9]),
c = this.gf(),
d = this.gf([1]),
e = this.gf(),
f = this.gf(),
_121665 = this.gf([0xdb41, 1]),
_9 = this.gf([9]);
for (var i = 0; i < 32; ++i)
z[i] = privateKey[i];
this.clamp(z);
for (var i = 254; i >= 0; --i) {
r = (z[i >>> 3] >>> (i & 7)) & 1;
this.cswap(a, b, r);
this.cswap(c, d, r);
this.add(e, a, c);
this.subtract(a, a, c);
this.add(c, b, d);
this.subtract(b, b, d);
this.multmod(d, e, e);
this.multmod(f, a, a);
this.multmod(a, c, a);
this.multmod(c, b, e);
this.add(e, a, c);
this.subtract(a, a, c);
this.multmod(b, a, a);
this.subtract(c, d, f);
this.multmod(a, c, _121665);
this.add(a, a, d);
this.multmod(c, c, a);
this.multmod(a, d, f);
this.multmod(d, b, _9);
this.multmod(b, e, e);
this.cswap(a, b, r);
this.cswap(c, d, r);
}
this.invert(c, c);
this.multmod(a, a, c);
this.pack(z, a);
return z;
}
static generatePresharedKey() {
var privateKey = new Uint8Array(32);
window.crypto.getRandomValues(privateKey);
return privateKey;
}
static generatePrivateKey() {
var privateKey = this.generatePresharedKey();
this.clamp(privateKey);
return privateKey;
}
static encodeBase64(dest, src) {
var input = Uint8Array.from([(src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63]);
for (var i = 0; i < 4; ++i)
dest[i] = input[i] + 65 +
(((25 - input[i]) >> 8) & 6) -
(((51 - input[i]) >> 8) & 75) -
(((61 - input[i]) >> 8) & 15) +
(((62 - input[i]) >> 8) & 3);
}
static keyToBase64(key) {
var i, base64 = new Uint8Array(44);
for (i = 0; i < 32 / 3; ++i)
this.encodeBase64(base64.subarray(i * 4), key.subarray(i * 3));
this.encodeBase64(base64.subarray(i * 4), Uint8Array.from([key[i * 3 + 0], key[i * 3 + 1], 0]));
base64[43] = 61;
return String.fromCharCode.apply(null, base64);
}
static keyFromBase64(encoded) {
const binaryStr = atob(encoded);
const bytes = new Uint8Array(binaryStr.length);
for (let i = 0; i < binaryStr.length; i++) {
bytes[i] = binaryStr.charCodeAt(i);
}
return bytes;
}
static generateKeypair(secretKey='') {
var privateKey = secretKey.length>0 ? this.keyFromBase64(secretKey) : this.generatePrivateKey();
var publicKey = this.generatePublicKey(privateKey);
return {
publicKey: this.keyToBase64(publicKey),
privateKey: secretKey.length>0 ? secretKey : this.keyToBase64(privateKey)
};
}
}

View File

@@ -26,6 +26,7 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
g.POST("/update", a.updateSetting)
g.GET("/getXrayResult", a.getXrayResult)
g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
g.POST("/warp/:action", a.warp)
}
func (a *XraySettingController) getXraySetting(c *gin.Context) {
@@ -61,3 +62,25 @@ func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) {
func (a *XraySettingController) getXrayResult(c *gin.Context) {
jsonObj(c, a.XrayService.GetXrayResult(), nil)
}
func (a *XraySettingController) warp(c *gin.Context) {
action := c.Param("action")
var resp string
var err error
switch action {
case "data":
resp, err = a.XraySettingService.GetWarp()
case "config":
resp, err = a.XraySettingService.GetWarpConfig()
case "reg":
skey := c.PostForm("privateKey")
pkey := c.PostForm("publicKey")
resp, err = a.XraySettingService.RegWarp(skey, pkey)
case "license":
license := c.PostForm("license")
println(license)
resp, err = a.XraySettingService.SetWarpLicence(license)
}
jsonObj(c, resp, err)
}

View File

@@ -211,4 +211,4 @@
},
});
</script>
{{end}}
{{end}}

View File

@@ -19,7 +19,7 @@
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.client.renew" }}</span>
<span>{{ i18n "reset" }}</span>
</template>
{{ i18n "password" }}
<a-icon v-if="inbound.protocol === Protocols.SHADOWSOCKS" @click="client.password = RandomUtil.randomShadowsocksPassword()" type="sync"></a-icon>
@@ -32,7 +32,7 @@
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.client.renew" }}</span>
<span>{{ i18n "reset" }}</span>
</template>
ID <a-icon @click="client.id = RandomUtil.randomUUID()" type="sync"></a-icon>
</a-tooltip>
@@ -75,7 +75,7 @@
<template slot="title">
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
</template>
{{ i18n "pages.inbounds.totalFlow" }}(GB)
{{ i18n "pages.inbounds.totalFlow" }} (GB)
<a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
@@ -122,4 +122,4 @@
<a-input-number v-model.number="client.reset" :min="0"></a-input-number>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -37,7 +37,7 @@
<template slot="title">
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
</template>
{{ i18n "pages.inbounds.totalFlow" }}(GB)
{{ i18n "pages.inbounds.totalFlow" }} (GB)
<a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
@@ -95,6 +95,11 @@
{{template "form/http"}}
</template>
<!-- wireguard -->
<template v-if="inbound.protocol === Protocols.WIREGUARD">
{{template "form/wireguard"}}
</template>
<!-- stream settings -->
<template v-if="inbound.canEnableStream()">
{{template "form/streamSettings"}}
@@ -110,4 +115,4 @@
<template v-if="inbound.canSniffing()">
{{template "form/sniffing"}}
</template>
{{end}}
{{end}}

View File

@@ -18,7 +18,7 @@
<a-select
v-model="outbound.settings.domainStrategy"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="s in outboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
<a-select-option v-for="s in OutboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Fragment'>
@@ -66,6 +66,96 @@
</a-form-item>
</template>
<!-- wireguard settings -->
<template v-if="outbound.protocol === Protocols.Wireguard">
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template>
{{ i18n "pages.xray.outbound.address" }} <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="outbound.settings.address"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template>
{{ i18n "pages.xray.wireguard.secretKey" }}
<a-icon type="sync"
@click="[outbound.settings.pubKey, outbound.settings.secretKey] = Object.values(Wireguard.generateKeypair())">
</a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="outbound.settings.secretKey"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.wireguard.publicKey" }}'>
<a-input disabled v-model="outbound.settings.pubKey"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.wireguard.domainStrategy" }}'>
<a-select v-model="outbound.settings.domainStrategy" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="wds in ['', ...WireguardDomainStrategy]" :value="wds">[[ wds ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='MTU'>
<a-input-number v-model.number="outbound.settings.mtu"></a-input-number>
</a-form-item>
<a-form-item label='Workers'>
<a-input-number min="0" v-model.number="outbound.settings.workers"></a-input>
</a-form-item>
<a-form-item label='Kernel Mode'>
<a-switch v-model="outbound.settings.kernelMode"></a-switch>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template>
Reserved <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model="outbound.settings.reserved"></a-input>
</a-form-item>
<a-form-item label="Peers">
<a-button type="primary" size="small" @click="outbound.settings.addPeer()">+</a-button>
</a-form-item>
<a-form v-for="(peer, index) in outbound.settings.peers" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;">
Peer [[ index + 1 ]]
<a-icon v-if="outbound.settings.peers.length>1" type="delete" @click="() => outbound.settings.delPeer(index)"
style="color: rgb(255, 77, 79);cursor: pointer;"/>
</a-divider>
<a-form-item label='{{ i18n "pages.xray.wireguard.endpoint" }}'>
<a-input v-model.trim="peer.endpoint"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.wireguard.publicKey" }}'>
<a-input v-model.trim="peer.publicKey"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.wireguard.psk" }}'>
<a-input v-model.trim="peer.psk"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
{{ i18n "pages.xray.wireguard.allowedIPs" }} <a-button type="primary" size="small" @click="peer.allowedIPs.push('')">+</a-button>
</template>
<template v-for="(aip, index) in peer.allowedIPs" style="margin-bottom: 10px;">
<a-input v-model.trim="peer.allowedIPs[index]">
<a-button v-if="peer.allowedIPs.length>1" slot="addonAfter" size="small" @click="peer.allowedIPs.splice(index, 1)">-</a-button>
</a-input>
</template>
</a-form-item>
<a-form-item label='Keep Alive'>
<a-input-number v-model.number="peer.keepAlive" :min="0"></a-input>
</a-form-item>
</a-form>
</template>
<!-- Address + Port -->
<template v-if="outbound.hasAddressPort()">
<a-form-item label='{{ i18n "pages.inbounds.address" }}'>
@@ -94,19 +184,20 @@
<!-- Servers (trojan/shadowsocks/socks/http) settings -->
<template v-if="outbound.hasServers()">
<!-- http / socks -->
<template v-if="outbound.hasUsername()">
<a-form-item label='{{ i18n "username" }}'>
<a-input v-model.trim="outbound.settings.user"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "password" }}'>
<a-input v-model.trim="outbound.settings.password"></a-input>
<a-input v-model.trim="outbound.settings.pass"></a-input>
</a-form-item>
</template>
<!-- shadowsocks -->
<template v-if="outbound.protocol === Protocols.Shadowsocks">
<a-form-item label='{{ i18n "encryption" }}'>
<a-select v-model="outbound.settings.method" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option>
<a-select-option v-for="(method,method_name) in SSMethods" :value="method">[[ method_name ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='UDP over TCP'>
@@ -121,15 +212,15 @@
<a-select v-model="outbound.stream.network" @change="streamNetworkChange"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp">TCP</a-select-option>
<a-select-option value="kcp">KCP</a-select-option>
<a-select-option value="kcp">mKCP</a-select-option>
<a-select-option value="ws">WebSocket</a-select-option>
<a-select-option value="http">HTTP2</a-select-option>
<a-select-option value="http">HTTP/2</a-select-option>
<a-select-option value="quic">QUIC</a-select-option>
<a-select-option value="grpc">gRPC</a-select-option>
</a-select>
</a-form-item>
<template v-if="outbound.stream.network === 'tcp'">
<a-form-item label='http {{ i18n "camouflage" }}'>
<a-form-item label='HTTP {{ i18n "camouflage" }}'>
<a-switch
:checked="outbound.stream.tcp.type === 'http'"
@change="checked => outbound.stream.tcp.type = checked ? 'http' : 'none'">
@@ -149,36 +240,36 @@
<template v-if="outbound.stream.network === 'kcp'">
<a-form-item label='{{ i18n "camouflage" }}'>
<a-select v-model="outbound.stream.kcp.type" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">none (not camouflage)</a-select-option>
<a-select-option value="srtp">srtp (video call)</a-select-option>
<a-select-option value="utp">utp (BT download)</a-select-option>
<a-select-option value="wechat-video">wechat-video (WeChat video)</a-select-option>
<a-select-option value="dtls">dtls (DTLS 1.2 packages)</a-select-option>
<a-select-option value="wireguard">wireguard (wireguard packages)</a-select-option>
<a-select-option value="none">None</a-select-option>
<a-select-option value="srtp">SRTP</a-select-option>
<a-select-option value="utp">uTP</a-select-option>
<a-select-option value="wechat-video">WeChat</a-select-option>
<a-select-option value="dtls">DTLS 1.2</a-select-option>
<a-select-option value="wireguard">WireGuard</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='{{ i18n "password" }}'>
<a-input v-model="outbound.stream.kcp.seed"></a-input>
</a-form-item>
<a-form-item label='mtu'>
<a-form-item label='MTU'>
<a-input-number v-model.number="outbound.stream.kcp.mtu"></a-input-number>
</a-form-item>
<a-form-item label='tti (ms)'>
<a-form-item label='TTI (ms)'>
<a-input-number v-model.number="outbound.stream.kcp.tti"></a-input-number>
</a-form-item>
<a-form-item label='uplink capacity (MB/S)'>
<a-form-item label='Uplink (MB/s)'>
<a-input-number v-model.number="outbound.stream.kcp.upCap"></a-input-number>
</a-form-item>
<a-form-item label='downlink capacity (MB/S)'>
<a-form-item label='Downlink (MB/s)'>
<a-input-number v-model.number="outbound.stream.kcp.downCap"></a-input-number>
</a-form-item>
<a-form-item label='congestion'>
<a-form-item label='Congestion'>
<a-switch v-model="outbound.stream.kcp.congestion"></a-switch>
</a-form-item>
<a-form-item label='read buffer size (MB)'>
<a-form-item label='Read Buffer (MB)'>
<a-input-number v-model.number="outbound.stream.kcp.readBuffer"></a-input-number>
</a-form-item>
<a-form-item label='write buffer size (MB)'>
<a-form-item label='Write Buffer (MB)'>
<a-input-number v-model.number="outbound.stream.kcp.writeBuffer"></a-input-number>
</a-form-item>
</template>
@@ -207,9 +298,9 @@
<template v-if="outbound.stream.network === 'quic'">
<a-form-item label='{{ i18n "pages.inbounds.stream.quic.encryption" }}'>
<a-select v-model="outbound.stream.quic.security" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">none</a-select-option>
<a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option>
<a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option>
<a-select-option value="none">None</a-select-option>
<a-select-option value="aes-128-gcm">AES-128-GCM</a-select-option>
<a-select-option value="chacha20-poly1305">CHACHA20-POLY1305</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='{{ i18n "password" }}'>
@@ -217,22 +308,22 @@
</a-form-item>
<a-form-item label='{{ i18n "camouflage" }}'>
<a-select v-model="outbound.stream.quic.type" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">none (not camouflage)</a-select-option>
<a-select-option value="srtp">srtp (video call)</a-select-option>
<a-select-option value="utp">utp (BT download)</a-select-option>
<a-select-option value="wechat-video">wechat-video (WeChat video)</a-select-option>
<a-select-option value="dtls">dtls (DTLS 1.2 packages)</a-select-option>
<a-select-option value="wireguard">wireguard (wireguard packages)</a-select-option>
<a-select-option value="none">None</a-select-option>
<a-select-option value="srtp">SRTP</a-select-option>
<a-select-option value="utp">uTP</a-select-option>
<a-select-option value="wechat-video">WeChat</a-select-option>
<a-select-option value="dtls">DTLS 1.2</a-select-option>
<a-select-option value="wireguard">WireGuard</a-select-option>
</a-select>
</a-form-item>
</template>
<!-- grpc -->
<template v-if="outbound.stream.network === 'grpc'">
<a-form-item label='serviceName'>
<a-form-item label='Service Name'>
<a-input v-model.trim="outbound.stream.grpc.serviceName"></a-input>
</a-form-item>
<a-form-item label='MultiMode'>
<a-form-item label='Multi Mode'>
<a-switch v-model="outbound.stream.grpc.multiMode"></a-switch>
</a-form-item>
</template>
@@ -267,7 +358,7 @@
<a-select-option v-for="alpn in ALPN_OPTION" :value="alpn">[[ alpn ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Allow insecure">
<a-form-item label="Allow Insecure">
<a-switch v-model="outbound.stream.tls.allowInsecure"></a-switch>
</a-form-item>
</template>
@@ -283,7 +374,7 @@
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Short Id">
<a-form-item label="Short ID">
<a-input v-model.trim="outbound.stream.reality.shortId" style="width:250px"></a-input>
</a-form-item>
<a-form-item label="SpiderX">
@@ -304,4 +395,4 @@
<textarea style="position:absolute; left: -800px;" id="outboundJson"></textarea>
</a-tab-pane>
</a-tabs>
{{end}}
{{end}}

View File

@@ -8,13 +8,13 @@
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.network"}}'>
<a-select v-model="inbound.settings.network" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp,udp">tcp+udp</a-select-option>
<a-select-option value="tcp">tcp</a-select-option>
<a-select-option value="udp">udp</a-select-option>
<a-select-option value="tcp,udp">TCP+UDP</a-select-option>
<a-select-option value="tcp">TCP</a-select-option>
<a-select-option value="udp">UDP</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='FollowRedirect'>
<a-form-item label='Follow Redirect'>
<a-switch v-model="inbound.settings.followRedirect"></a-switch>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -20,38 +20,31 @@
</a-collapse-panel>
</a-collapse>
</template>
<table width="100%" class="ant-table-tbody">
<tr>
<td>{{ i18n "encryption" }}</td>
<td>
<a-form-item>
<a-select v-model="inbound.settings.method" style="width: 250px;" @change="SSMethodChange" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option>
</a-select>
</a-form-item>
</td>
</tr>
<tr v-if="inbound.isSS2022">
<td>{{ i18n "password" }}
<a-icon @click="inbound.settings.password = RandomUtil.randomShadowsocksPassword()" type="sync"> </a-icon>
</td>
<td>
<a-form-item>
<a-input v-model.trim="inbound.settings.password" style="width: 250px"></a-input>
</a-form-item>
</td>
</tr>
<tr>
<td>{{ i18n "pages.inbounds.network" }}</td>
<td>
<a-form-item>
<a-select v-model="inbound.settings.network" style="width: 100px;" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp,udp">tcp+udp</a-select-option>
<a-select-option value="tcp">tcp</a-select-option>
<a-select-option value="udp">udp</a-select-option>
</a-select>
</a-form-item>
</td>
</tr>
</table>
{{end}}
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "encryption" }}'>
<a-select v-model="inbound.settings.method" @change="SSMethodChange" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="(method,method_name) in SSMethods" :value="method">[[ method_name ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item v-if="inbound.isSS2022">
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template>
{{ i18n "password" }}
<a-icon @click="client.password = RandomUtil.randomShadowsocksPassword()" type="sync"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="inbound.settings.password"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.network" }}'>
<a-select v-model="inbound.settings.network" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp,udp">TCP+UDP</a-select-option>
<a-select-option value="tcp">TCP</a-select-option>
<a-select-option value="udp">UDP</a-select-option>
</a-select>
</a-form-item>
</a-form>
<a-divider style="margin:0;"></a-divider>
{{end}}

View File

@@ -1,6 +1,6 @@
{{define "form/socks"}}
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "pages.inbounds.enable" }} udp'>
<a-form-item label='{{ i18n "pages.inbounds.enable" }} UDP'>
<a-switch v-model="inbound.settings.udp"></a-switch>
</a-form-item>
<a-form-item label="IP" v-if="inbound.settings.udp">
@@ -30,4 +30,4 @@
</a-input-group>
</template>
</a-form>
{{end}}
{{end}}

View File

@@ -33,14 +33,14 @@
<!-- trojan fallbacks -->
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;">
fallback[[ index + 1 ]]
Fallback [[ index + 1 ]]
<a-icon type="delete" @click="() => inbound.settings.delFallback(index)"
style="color: rgb(255, 77, 79);cursor: pointer;"/>
</a-divider>
<a-form-item label='Name'>
<a-form-item label='SNI'>
<a-input v-model="fallback.name"></a-input>
</a-form-item>
<a-form-item label='Alpn'>
<a-form-item label='ALPN'>
<a-input v-model="fallback.alpn"></a-input>
</a-form-item>
<a-form-item label='Path'>
@@ -55,4 +55,4 @@
</a-form>
<a-divider style="margin:0;"></a-divider>
</template>
{{end}}
{{end}}

View File

@@ -35,14 +35,14 @@
<!-- vless fallbacks -->
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;">
fallback[[ index + 1 ]]
Fallback [[ index + 1 ]]
<a-icon type="delete" @click="() => inbound.settings.delFallback(index)"
style="color: rgb(255, 77, 79);cursor: pointer;"/>
</a-divider>
<a-form-item label='Name'>
<a-form-item label='SNI'>
<a-input v-model="fallback.name"></a-input>
</a-form-item>
<a-form-item label='Alpn'>
<a-form-item label='ALPN'>
<a-input v-model="fallback.alpn"></a-input>
</a-form-item>
<a-form-item label='Path'>

View File

@@ -0,0 +1,56 @@
{{define "form/wireguard"}}
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template>
{{ i18n "pages.xray.wireguard.secretKey" }}
<a-icon type="sync"
@click="[inbound.settings.pubKey, inbound.settings.secretKey] = Object.values(Wireguard.generateKeypair())">
</a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="inbound.settings.secretKey"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.wireguard.publicKey" }}'>
<a-input disabled v-model="inbound.settings.pubKey"></a-input>
</a-form-item>
<a-form-item label='MTU'>
<a-input-number v-model.number="inbound.settings.mtu"></a-input-number>
</a-form-item>
<a-form-item label='Kernel Mode'>
<a-switch v-model="inbound.settings.kernelMode"></a-switch>
</a-form-item>
<a-form-item label="Peers">
<a-button type="primary" size="small" @click="inbound.settings.addPeer()">+</a-button>
</a-form-item>
<a-form v-for="(peer, index) in inbound.settings.peers" :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;">
Peer [[ index + 1 ]]
<a-icon v-if="inbound.settings.peers.length>1" type="delete" @click="() => inbound.settings.delPeer(index)"
style="color: rgb(255, 77, 79);cursor: pointer;"/>
</a-divider>
<a-form-item label='{{ i18n "pages.xray.wireguard.publicKey" }}'>
<a-input v-model.trim="peer.publicKey"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.wireguard.psk" }}'>
<a-input v-model.trim="peer.psk"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
{{ i18n "pages.xray.wireguard.allowedIPs" }} <a-button type="primary" size="small" @click="peer.allowedIPs.push('')">+</a-button>
</template>
<template v-for="(aip, index) in peer.allowedIPs" style="margin-bottom: 10px;">
<a-input v-model.trim="peer.allowedIPs[index]">
<a-button v-if="peer.allowedIPs.length>1" slot="addonAfter" size="small" @click="peer.allowedIPs.splice(index, 1)">-</a-button>
</a-input>
</template>
</a-form-item>
<a-form-item label='Keep Alive'>
<a-input-number v-model.number="peer.keepAlive" :min="0"></a-input>
</a-form-item>
</a-form>
</a-form>
{{end}}

View File

@@ -3,8 +3,8 @@
<a-form-item label="Service Name">
<a-input v-model.trim="inbound.stream.grpc.serviceName" style="width: 250px;"></a-input>
</a-form-item>
<a-form-item label="MultiMode">
<a-form-item label="Multi Mode">
<a-switch v-model="inbound.stream.grpc.multiMode"></a-switch>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -2,37 +2,46 @@
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "camouflage" }}'>
<a-select v-model="inbound.stream.kcp.type" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">none (not camouflage)</a-select-option>
<a-select-option value="srtp">srtp (video call)</a-select-option>
<a-select-option value="utp">utp (BT download)</a-select-option>
<a-select-option value="wechat-video">wechat-video (WeChat video)</a-select-option>
<a-select-option value="dtls">dtls (DTLS 1.2 packages)</a-select-option>
<a-select-option value="wireguard">wireguard (wireguard packages)</a-select-option>
<a-select-option value="none">None</a-select-option>
<a-select-option value="srtp">SRTP</a-select-option>
<a-select-option value="utp">uTP</a-select-option>
<a-select-option value="wechat-video">WeChat</a-select-option>
<a-select-option value="dtls">DTLS 1.2</a-select-option>
<a-select-option value="wireguard">WireGuard</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='{{ i18n "password" }}'>
<a-input v-model="inbound.stream.kcp.seed"></a-input>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template>
{{ i18n "password" }}
<a-icon @click="inbound.stream.kcp.seed = RandomUtil.randomSeq(10)"type="sync"> </a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="inbound.stream.kcp.seed"></a-input>
</a-form-item>
<a-form-item label='MTU'>
<a-input-number v-model.number="inbound.stream.kcp.mtu"></a-input-number>
</a-form-item>
<a-form-item label='TTI(ms)'>
<a-form-item label='TTI (ms)'>
<a-input-number v-model.number="inbound.stream.kcp.tti"></a-input-number>
</a-form-item>
<a-form-item label='Uplink(Mb/s)'>
<a-form-item label='Uplink (MB/s)'>
<a-input-number v-model.number="inbound.stream.kcp.upCap"></a-input-number>
</a-form-item>
<a-form-item label='Downlink(Mb/s)'>
<a-form-item label='Downlink (MB/s)'>
<a-input-number v-model.number="inbound.stream.kcp.downCap"></a-input-number>
</a-form-item>
<a-form-item label='Congestion'>
<a-switch v-model="inbound.stream.kcp.congestion"></a-switch>
</a-form-item>
<a-form-item label='Read buffer(MB)'>
<a-form-item label='Read Buffer (MB)'>
<a-input-number v-model.number="inbound.stream.kcp.readBuffer"></a-input-number>
</a-form-item>
<a-form-item label='Write buffer(MB)'>
<a-form-item label='Write Buffer (MB)'>
<a-input-number v-model.number="inbound.stream.kcp.writeBuffer"></a-input-number>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -2,23 +2,32 @@
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "pages.inbounds.stream.quic.encryption" }}'>
<a-select v-model="inbound.stream.quic.security" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">none</a-select-option>
<a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option>
<a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option>
<a-select-option value="none">None</a-select-option>
<a-select-option value="aes-128-gcm">AES-128-GCM</a-select-option>
<a-select-option value="chacha20-poly1305">CHACHA20-POLY1305</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='{{ i18n "password" }}'>
<a-input v-model.trim="inbound.stream.quic.key"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "reset" }}</span>
</template>
{{ i18n "password" }}
<a-icon @click="inbound.stream.quic.key = RandomUtil.randomSeq(10)"type="sync"> </a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="inbound.stream.quic.key"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "camouflage" }}'>
<a-select v-model="inbound.stream.quic.type" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">none (not camouflage)</a-select-option>
<a-select-option value="srtp">srtp (video call)</a-select-option>
<a-select-option value="utp">utp (BT download)</a-select-option>
<a-select-option value="wechat-video">wechat-video (WeChat video)</a-select-option>
<a-select-option value="dtls">dtls (DTLS 1.2 packages)</a-select-option>
<a-select-option value="wireguard">wireguard (wireguard packages)</a-select-option>
<a-select-option value="none">None</a-select-option>
<a-select-option value="srtp">SRTP</a-select-option>
<a-select-option value="utp">uTP</a-select-option>
<a-select-option value="wechat-video">WeChat</a-select-option>
<a-select-option value="dtls">DTLS 1.2</a-select-option>
<a-select-option value="wireguard">WireGuard</a-select-option>
</a-select>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -5,9 +5,9 @@
<a-select v-model="inbound.stream.network" @change="streamNetworkChange"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp">TCP</a-select-option>
<a-select-option value="kcp">KCP</a-select-option>
<a-select-option value="kcp">mKCP</a-select-option>
<a-select-option value="ws">WebSocket</a-select-option>
<a-select-option value="http">HTTP2</a-select-option>
<a-select-option value="http">HTTP/2</a-select-option>
<a-select-option value="quic">QUIC</a-select-option>
<a-select-option value="grpc">gRPC</a-select-option>
</a-select>
@@ -47,4 +47,4 @@
<template>
{{template "form/streamSockopt"}}
</template>
{{end}}
{{end}}

View File

@@ -1,26 +1,26 @@
{{define "form/streamSockopt"}}
<a-divider style="margin:0;"></a-divider>
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="Transparent Proxy">
<a-form-item label="TPROXY">
<a-switch v-model="inbound.stream.sockoptSwitch"></a-switch>
</a-form-item>
<template v-if="inbound.stream.sockoptSwitch">
<a-form-item label="Accept Proxy Protocol">
<a-form-item label="PROXY Protocol">
<a-switch v-model="inbound.stream.sockopt.acceptProxyProtocol"></a-switch>
</a-form-item>
<a-form-item label="TCP FastOpen">
<a-form-item label="TCP Fast Open">
<a-switch v-model.trim="inbound.stream.sockopt.tcpFastOpen"></a-switch>
</a-form-item>
<a-form-item label="Route Mark">
<a-input-number v-model="inbound.stream.sockopt.mark" :min="0"></a-input-number>
</a-form-item>
<a-form-item label="T-Proxy">
<a-form-item label="TPROXY">
<a-select v-model="inbound.stream.sockopt.tproxy" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="off">OFF</a-select-option>
<a-select-option value="off">Off</a-select-option>
<a-select-option value="redirect">Redirect</a-select-option>
<a-select-option value="tproxy">T-Proxy</a-select-option>
<a-select-option value="tproxy">TPROXY</a-select-option>
</a-select>
</a-form-item>
</template>
</a-form>
{{end}}
{{end}}

View File

@@ -1,10 +1,10 @@
{{define "form/streamTCP"}}
<!-- tcp type -->
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="Accept Proxy Protocol" v-if="inbound.canEnableTls()">
<a-form-item label="PROXY Protocol" v-if="inbound.canEnableTls()">
<a-switch v-model="inbound.stream.tcp.acceptProxyProtocol"></a-switch>
</a-form-item>
<a-form-item label="http {{ i18n "camouflage" }}">
<a-form-item label="HTTP {{ i18n "camouflage" }}">
<a-switch
:checked="inbound.stream.tcp.type === 'http'"
@change="checked => inbound.stream.tcp.type = checked ? 'http' : 'none'">
@@ -12,8 +12,9 @@
</a-form-item>
</a-form>
<!-- tcp request -->
<a-form v-if="inbound.stream.tcp.type === 'http'" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<!-- tcp request -->
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.general.requestHeader" }}</a-divider>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestVersion" }}'>
<a-input v-model.trim="inbound.stream.tcp.request.version"></a-input>
</a-form-item>
@@ -45,7 +46,8 @@
</a-input>
</a-input-group>
</a-form-item>
<!-- tcp response -->
<!-- tcp response -->
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}</a-divider>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseVersion" }}'>
<a-input v-model.trim="inbound.stream.tcp.response.version"></a-input>
</a-form-item>
@@ -73,4 +75,4 @@
</a-input-group>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -1,6 +1,6 @@
{{define "form/streamWS"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="AcceptProxyProtocol">
<a-form-item label="PROXY Protocol">
<a-switch v-model="inbound.stream.ws.acceptProxyProtocol"></a-switch>
</a-form-item>
<a-form-item label='{{ i18n "path" }}'>
@@ -20,4 +20,4 @@
</a-input-group>
</a-form-item>
</a-form>
{{end}}
{{end}}

View File

@@ -15,9 +15,9 @@
<a-form-item label="SNI" placeholder="Server Name Indication">
<a-input v-model.trim="inbound.stream.tls.sni"></a-input>
</a-form-item>
<a-form-item label="CipherSuites">
<a-form-item label="Cipher Suites">
<a-select v-model="inbound.stream.tls.cipherSuites" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="">auto</a-select-option>
<a-select-option value="">Auto</a-select-option>
<a-select-option v-for="key,value in TLS_CIPHER_OPTION" :value="key">[[ value ]]</a-select-option>
</a-select>
</a-form-item>
@@ -46,7 +46,7 @@
<a-select-option v-for="alpn in ALPN_OPTION" :value="alpn">[[ alpn ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Allow insecure">
<a-form-item label="Allow Insecure">
<a-switch v-model="inbound.stream.tls.settings.allowInsecure"></a-switch>
</a-form-item>
<a-form-item label="Reject Unknown SNI">
@@ -80,7 +80,7 @@
<a-input type="textarea" :rows="3" style="width:250px;" v-model="cert.key"></a-input>
</a-form-item>
</template>
<a-form-item label='ocspStapling'>
<a-form-item label='OCSP stapling'>
<a-input-number v-model.number="cert.ocspStapling" :min="0"></a-input-number>
</a-form-item>
</template>
@@ -103,16 +103,16 @@
<a-form-item label='Dest'>
<a-input v-model.trim="inbound.stream.reality.dest"></a-input>
</a-form-item>
<a-form-item label='Server Names'>
<a-form-item label='SNI'>
<a-input v-model.trim="inbound.stream.reality.serverNames"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.client.renew" }}</span>
<span>{{ i18n "reset" }}</span>
</template>
Short Ids
Short IDs
<a-icon @click="inbound.stream.reality.shortIds = RandomUtil.randomShortId().join(',')" type="sync">
</a-icon>
</template>
@@ -128,8 +128,8 @@
<a-input v-model.trim="inbound.stream.reality.settings.publicKey"></a-input>
</a-form-item>
<a-form-item label=" ">
<a-button type="primary" icon="import" @click="getNewX25519Cert">Get new cert</a-button>
<a-button type="primary" icon="import" @click="getNewX25519Cert">Get New Cert</a-button>
</a-form-item>
</template>
</a-form>
{{end}}
{{end}}

View File

@@ -160,7 +160,7 @@
</tr>
</table>
<template v-if="app.subSettings.enable && infoModal.clientSettings.subId">
<a-divider>Subscription link</a-divider>
<a-divider>Subscription URL</a-divider>
<a-row>
<a-col :sx="24" :md="22"><a :href="[[ infoModal.subLink ]]" target="_blank">[[ infoModal.subLink ]]</a></a-col>
<a-col :sx="24" :md="2" style="text-align: right;">
@@ -260,6 +260,45 @@
<td><a-tag color="blue">[[ account.pass ]]</a-tag></td>
</tr>
</table>
<table v-if="dbInbound.isWireguard" style="margin-bottom: 10px; width: 100%;">
<tr class="client-table-odd-row">
<td>{{ i18n "pages.xray.wireguard.secretKey" }}</td>
<td>[[ inbound.settings.secretKey ]]</td>
</tr>
<tr>
<td>{{ i18n "pages.xray.wireguard.publicKey" }}</td>
<td>[[ inbound.settings.pubKey ]]</td>
</tr>
<tr class="client-table-odd-row">
<td>MTU</td>
<td>[[ inbound.settings.mtu ]]</td>
</tr>
<tr>
<td>Kernel Mode</td>
<td>[[ inbound.settings.kernelMode ]]</td>
</tr>
<template v-for="(peer, index) in inbound.settings.peers">
<tr>
<td colspan="2"><a-tag>Peer [[ index + 1 ]]</a-tag></td>
</tr>
<tr class="client-table-odd-row">
<td>{{ i18n "pages.xray.wireguard.publicKey" }}</td>
<td>[[ peer.publicKey ]]</td>
</tr>
<tr>
<td>{{ i18n "pages.xray.wireguard.psk" }}</td>
<td>[[ peer.psk ]]</td>
</tr>
<tr class="client-table-odd-row">
<td>{{ i18n "pages.xray.wireguard.allowedIPs" }}</td>
<td>[[ peer.allowedIPs.join(",") ]]</td>
</tr>
<tr>
<td>Keep Alive</td>
<td>[[ peer.keepAlive ]]</td>
</tr>
</table>
</template>
</template>
</a-modal>
<script>
@@ -345,4 +384,4 @@
});
</script>
{{end}}
{{end}}

View File

@@ -164,9 +164,9 @@
</a-col>
</a-row>
</div>
<div style="display: flex; align-items: center; justify-content: flex-start;">
<div :style="isMobile ? '' : 'display: flex; align-items: center; justify-content: flex-start;'">
<a-switch v-model="enableFilter"
style="margin-right: .5rem;"
:style="isMobile ? 'margin-bottom: .5rem; display: flex;' : 'margin-right: .5rem;'"
@change="toggleFilter">
<a-icon slot="checkedChildren" type="search"></a-icon>
<a-icon slot="unCheckedChildren" type="filter"></a-icon>
@@ -1032,6 +1032,7 @@
},
switchEnable(dbInboundId) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
dbInbound.enable = !dbInbound.enable;
this.submit(`/xui/inbound/update/${dbInboundId}`, dbInbound);
},
async switchEnableClient(dbInboundId, client) {

View File

@@ -44,7 +44,7 @@
<a-progress type="dashboard" status="normal"
:stroke-color="status.cpu.color"
:percent="status.cpu.percent"></a-progress>
<div>CPU: ([[ status.cpuCount ]]core)</div>
<div>CPU: [[ cpuCoreFormat(status.cpuCount) ]]</div>
</a-col>
<a-col :span="12" style="text-align: center">
<a-progress type="dashboard" status="normal"
@@ -83,9 +83,9 @@
<transition name="list" appear>
<a-row>
<a-col :sm="24" :md="12">
<a-card hoverable>
X-UI: <a href="https://github.com/alireza0/x-ui/releases" target="_blank"><a-tag color="blue">{{ .cur_ver }}</a-tag></a>
Xray:
<a-card hoverable>
X-UI <a href="https://github.com/alireza0/x-ui/releases" target="_blank"><a-tag color="blue">{{ .cur_ver }}</a-tag></a>
Xray
<a-tooltip title='{{ i18n "pages.index.xraySwitch" }}'>
<a-tag color="blue" style="cursor: pointer;" @click="openSelectV2rayVersion">[[ status.xray.version ]]</a-tag>
</a-tooltip>
@@ -112,7 +112,7 @@
<a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag>
<a-popover v-if="status.xray.state === State.Error"
:overlay-class-name="themeSwitcher.currentTheme">
<span slot="title" style="font-size: 12pt">Error in running xray-core
<span slot="title" style="font-size: 12pt">An error occurred while running Xray
<a-tag color="purple" style="cursor: pointer; float: right;" @click="openLogs()">{{ i18n "pages.index.logs" }}</a-tag>
</span>
<template slot="content">
@@ -140,7 +140,7 @@
<a-col :sm="24" :md="12">
<a-card hoverable>
{{ i18n "usage"}}:
Memory: [[ sizeFormat(status.appStats.mem) ]] -
RAM: [[ sizeFormat(status.appStats.mem) ]] -
Threads: [[ status.appStats.threads ]]
</a-tooltip>
</a-card>
@@ -195,7 +195,7 @@
<a-row>
<a-col :span="12">
<a-icon type="arrow-up"></a-icon>
[[ sizeFormat(status.netIO.up) ]] / S
[[ sizeFormat(status.netIO.up) ]]/s
<a-tooltip>
<template slot="title">
{{ i18n "pages.index.upSpeed" }}
@@ -205,7 +205,7 @@
</a-col>
<a-col :span="12">
<a-icon type="arrow-down"></a-icon>
[[ sizeFormat(status.netIO.down) ]] / S
[[ sizeFormat(status.netIO.down) ]]/s
<a-tooltip>
<template slot="title">
{{ i18n "pages.index.downSpeed" }}
@@ -251,8 +251,10 @@
:closable="true" @ok="() => versionModal.visible = false"
:class="themeSwitcher.currentTheme"
footer="">
<h2>{{ i18n "pages.index.xraySwitchClick"}}</h2>
<h2>{{ i18n "pages.index.xraySwitchClickDesk"}}</h2>
<a-alert type="warning" style="margin-bottom: 12px; width: fit-content"
message='{{ i18n "pages.index.xraySwitchClickDesk" }}'
show-icon
></a-alert>
<template v-for="version, index in versionModal.versions">
<a-tag :color="index % 2 == 0 ? 'purple' : 'blue'"
style="margin: 10px" @click="switchV2rayVersion(version)">

View File

@@ -134,40 +134,22 @@
</a-list>
</a-tab-pane>
<a-tab-pane key="2" tab='{{ i18n "pages.settings.userSettings"}}'>
<a-form style="padding: 20px;" layout="inline">
<a-row>
<a-col :xs="24" :md="8" style="margin-top: 8px;">{{ i18n "pages.settings.oldUsername"}}:</a-col>
<a-col :xs="24" :md="8">
<a-form-item>
<a-input v-model="user.oldUsername" style="width: 200px"></a-input>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :xs="24" :md="8" style="margin-top: 8px;">{{ i18n "pages.settings.currentPassword"}}:</a-col>
<a-col :xs="24" :md="8">
<a-form-item>
<password-input v-model="user.oldPassword" style="width: 200px"></password-input>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :xs="24" :md="8" style="margin-top: 8px;">{{ i18n "pages.settings.newUsername"}}:</a-col>
<a-col :xs="24" :md="8">
<a-form-item>
<a-input v-model="user.newUsername" style="width: 200px"></a-input>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :xs="24" :md="8" style="margin-top: 8px;">{{ i18n "pages.settings.newPassword"}}:</a-col>
<a-col :xs="24" :md="8">
<a-form-item>
<password-input v-model="user.newPassword" style="width: 200px"></password-input>
</a-form-item>
</a-col>
</a-row>
<a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button>
<a-form layout="horizontal" :colon="false" style="float: left; margin: 10px 0;" :label-col="{ md: {span:10} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "pages.settings.oldUsername"}}'>
<a-input v-model="user.oldUsername"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.settings.currentPassword"}}'>
<password-input v-model="user.oldPassword"></password-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.settings.newUsername"}}'>
<a-input v-model="user.newUsername"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.settings.newPassword"}}'>
<password-input v-model="user.newPassword"></password-input>
</a-form-item>
<a-form-item label=" ">
<a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button>
</a-form-item>
</a-form>
</a-tab-pane>
<a-tab-pane key="3" tab='{{ i18n "pages.settings.TGBotSettings"}}'>

View File

@@ -0,0 +1,204 @@
{{define "warpModal"}}
<a-modal id="warp-modal" v-model="warpModal.visible" title="Cloudflare WARP"
:confirm-loading="warpModal.confirmLoading" :closable="true" :mask-closable="true"
:footer="null" :class="themeSwitcher.currentTheme">
<template v-if="ObjectUtil.isEmpty(warpModal.warpData)">
<a-button icon="api" @click="register" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.create" }}</a-button>
</template>
<template v-else>
<table style="margin: 5px 0; width: 100%;">
<tr class="client-table-odd-row">
<td>Access Token</td>
<td>[[ warpModal.warpData.access_token ]]</td>
</tr>
<tr>
<td>Devide ID</td>
<td>[[ warpModal.warpData.device_id ]]</td>
</tr>
<tr class="client-table-odd-row">
<td>License Key</td>
<td>[[ warpModal.warpData.license_key ]]</td>
</tr>
<tr>
<td>Private Key</td>
<td>[[ warpModal.warpData.private_key ]]</td>
</tr>
</table>
<a-divider style="margin: 0;">{{ i18n "pages.settings.toasts.modifySettings" }}</a-divider>
<a-collapse style="margin: 10px 0;">
<a-collapse-panel header='WARP/WARP+ License Key'>
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="License Key">
<a-input v-model="warpPlus"></a-input>
<a-button @click="updateLicense(warpPlus)" :disabled="warpPlus.length<26" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.update" }}</a-button>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
<a-divider style="margin: 0;">{{ i18n "pages.settings.toasts.getSettings" }}</a-divider>
<a-button icon="sync" @click="getConfig" style="margin-bottom: 10px;" :loading="warpModal.confirmLoading">{{ i18n "info" }}</a-button>
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig)">
<table style="width: 100%">
<tr class="client-table-odd-row">
<td>Device Name</td>
<td>[[ warpModal.warpConfig.name ]]</td>
</tr>
<tr>
<td>Device Model</td>
<td>[[ warpModal.warpConfig.model ]]</td>
</tr>
<tr class="client-table-odd-row">
<td>Device Active</td>
<td>[[ warpModal.warpConfig.enabled ]]</td>
</tr>
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account)">
<tr>
<td>Account Type</td>
<td>[[ warpModal.warpConfig.account.account_type ]]</td>
</tr>
<tr class="client-table-odd-row">
<td>Role</td>
<td>[[ warpModal.warpConfig.account.role ]]</td>
</tr>
<tr>
<td>Premium Data</td>
<td>[[ sizeFormat(warpModal.warpConfig.account.premium_data) ]]</td>
</tr>
<tr class="client-table-odd-row">
<td>Quota</td>
<td>[[ sizeFormat(warpModal.warpConfig.account.quota) ]]</td>
</tr>
<tr v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account.usage)">
<td>Usage</td>
<td>[[ sizeFormat(warpModal.warpConfig.account.usage) ]]</td>
</tr>
</template>
</table>
<a-divider style="margin: 10px 0;">WARP {{ i18n "pages.xray.rules.outbound" }}</a-divider>
<a-form :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="{{ i18n "status" }}">
<template v-if="warpOutboundIndex>=0">
<a-tag color="green">{{ i18n "enabled" }}</a-tag>
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading">{{ i18n "reset" }}</a-button>
</template>
<template v-else>
<a-tag color="orange">{{ i18n "disabled" }}</a-tag>
<a-button @click="addOutbound" :loading="warpModal.confirmLoading">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
</template>
</a-form-item>
</a-form>
</template>
</template>
</a-modal>
<script>
const warpModal = {
visible: false,
confirmLoading: false,
warpData: null,
warpConfig: null,
warpOutbound: null,
show() {
this.visible = true;
this.warpConfig = null;
this.getData();
},
close() {
this.visible = false;
this.loading(false);
},
loading(loading) {
this.confirmLoading = loading;
},
async getData(){
this.loading(true);
const msg = await HttpUtil.post('/xui/xray/warp/data');
this.loading(false);
if (msg.success) {
this.warpData = msg.obj.length>0 ? JSON.parse(msg.obj): null;
}
},
};
new Vue({
delimiters: ['[[', ']]'],
el: '#warp-modal',
data: {
warpModal: warpModal,
warpPlus: '',
},
methods: {
collectConfig() {
config = warpModal.warpConfig.config;
peer = config.peers[0];
if(config){
warpModal.warpOutbound = Outbound.fromJson({
tag: 'warp',
protocol: Protocols.Wireguard,
settings: {
mtu: 1420,
secretKey: warpModal.warpData.private_key,
address: Object.values(config.interface.addresses),
peers: [{
publicKey: peer.public_key,
endpoint: peer.endpoint.host,
}],
kernelMode: false
}
});
}
},
async register(){
warpModal.loading(true);
keys = Wireguard.generateKeypair();
const msg = await HttpUtil.post('/xui/xray/warp/reg',keys);
if (msg.success) {
resp = JSON.parse(msg.obj);
warpModal.warpData = resp.data;
warpModal.warpConfig = resp.config;
this.collectConfig();
}
warpModal.loading(false);
},
async updateLicense(l){
warpModal.loading(true);
const msg = await HttpUtil.post('/xui/xray/warp/license',{license: l});
if (msg.success) {
warpModal.warpData = JSON.parse(msg.obj);
warpModal.warpConfig = null;
this.warpPlus = '';
}
warpModal.loading(false);
},
async getConfig(){
warpModal.loading(true);
const msg = await HttpUtil.post('/xui/xray/warp/config');
warpModal.loading(false);
if (msg.success) {
warpModal.warpConfig = JSON.parse(msg.obj);
this.collectConfig();
}
},
addOutbound(){
app.templateSettings.outbounds.push(warpModal.warpOutbound.toJson());
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
warpModal.close();
},
resetOutbound(){
app.templateSettings.outbounds[this.warpOutboundIndex] = warpModal.warpOutbound.toJson();
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
warpModal.close();
}
},
computed: {
warpOutboundIndex: {
get: function() {
return app.templateSettings ? app.templateSettings.outbounds.findIndex((o) => o.tag == 'warp') : -1;
}
}
}
});
</script>
{{end}}

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" href="{{ .base_path }}assets/codemirror/lint/lint.css">
<script src="{{ .base_path }}assets/base64/base64.min.js"></script>
<script src="{{ .base_path }}assets/js/model/outbound.js"></script>
<script src="{{ .base_path }}assets/js/model/outbound.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/codemirror/codemirror.js"></script>
<script src="{{ .base_path }}assets/codemirror/javascript.js"></script>
<script src="{{ .base_path }}assets/codemirror/jshint.js"></script>
@@ -103,7 +103,7 @@
</a-col>
</a-row>
</a-card>
<a-tabs default-active-key="1" @change="(activeKey) => { if(activeKey == 'tpl-4') this.changeCode(); }">
<a-tabs default-active-key="1" @change="(activeKey) => { if(activeKey == 'tpl-advanced') this.changeCode(); }">
<a-tab-pane key="tpl-1" tab='{{ i18n "pages.xray.basicTemplate"}}' style="padding-top: 20px;">
<a-collapse>
<a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'>
@@ -127,7 +127,7 @@
<a-select
v-model="freedomStrategy"
style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="s in outboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
<a-select-option v-for="s in OutboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
</a-select>
</template>
</a-col>
@@ -209,6 +209,23 @@
<setting-list-item type="switch" title='{{ i18n "pages.xray.GoogleIPv4"}}' desc='{{ i18n "pages.xray.GoogleIPv4Desc"}}' v-model="GoogleIPv4Settings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.xray.NetflixIPv4"}}' desc='{{ i18n "pages.xray.NetflixIPv4Desc"}}' v-model="NetflixIPv4Settings"></setting-list-item>
</a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.xray.warpConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center;">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
{{ i18n "pages.xray.warpConfigsDesc" }}
</template>
</a-alert>
</a-row>
<template v-if="WarpExist">
<setting-list-item type="switch" title='{{ i18n "pages.xray.GoogleWARP"}}' desc='{{ i18n "pages.xray.GoogleWARPDesc"}}' v-model="GoogleWARPSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.xray.OpenAIWARP"}}' desc='{{ i18n "pages.xray.OpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.xray.NetflixWARP"}}' desc='{{ i18n "pages.xray.NetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.xray.SpotifyWARP"}}' desc='{{ i18n "pages.xray.SpotifyWARPDesc"}}' v-model="SpotifyWARPSettings"></setting-list-item>
</template>
<a-button v-else style="margin: 10px 0;" @click="showWarp">WARP {{ i18n "pages.xray.rules.outbound" }}</a-button>
</a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.settings.resetDefaultConfig"}}'>
<a-space direction="horizontal" style="padding: 0 20px">
<a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
@@ -325,79 +342,74 @@
</a-table>
</a-tab-pane>
<a-tab-pane key="tpl-3" tab='{{ i18n "pages.xray.Outbounds"}}' style="padding-top: 20px;" force-render="true">
<a-button type="primary" icon="plus" @click="addOutbound()">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
<a-button type="primary" icon="plus" @click="addReverse()">{{ i18n "pages.xray.outbound.addReverse" }}</a-button>
<a-row>
<a-col :sm="24" :md="12">
<p style="margin: 10px;">{{ i18n "pages.xray.Outbounds"}}</p>
<a-table :columns="outboundColumns" bordered
:row-key="r => r.key"
:data-source="outboundData"
:scroll="isMobile ? {} : { x: 200 }"
:pagination="false"
:indent-size="0"
:style="isMobile ? 'padding: 5px 5px' : 'margin-right: 1px;'">
<template slot="action" slot-scope="text, outbound, index">
[[ index+1 ]]
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editOutbound(index)">
<a-icon type="edit"></a-icon>
{{ i18n "edit" }}
</a-menu-item>
<a-menu-item @click="deleteOutbound(index)">
<span style="color: #FF4D4F">
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template slot="address" slot-scope="text, outbound, index">
<p style="margin: 0 5px;" v-for="addr in findOutboundAddress(outbound)">[[ addr ]]</p>
</template>
<template slot="protocol" slot-scope="text, outbound, index">
<a-tag style="margin:0;" color="purple">[[ outbound.protocol ]]</a-tag>
<template v-if="[Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)">
<a-tag style="margin:0;" color="blue">[[ outbound.streamSettings.network ]]</a-tag>
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='tls'" color="green">tls</a-tag>
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='reality'" color="green">reality</a-tag>
</template>
</template>
</a-table>
</a-col>
<a-col :sm="24" :md="12" v-if="reverseData.length>0">
<p style="margin: 10px;">{{ i18n "pages.xray.outbound.reverse"}}</p>
<a-table :columns="reverseColumns" bordered
:row-key="r => r.key"
:data-source="reverseData"
:scroll="isMobile ? {} : { x: 200 }"
:pagination="false"
:indent-size="0"
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
<template slot="action" slot-scope="text, reverse, index">
[[ index+1 ]]
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editReverse(index)">
<a-icon type="edit"></a-icon>
{{ i18n "edit" }}
</a-menu-item>
<a-menu-item @click="deleteReverse(index)">
<span style="color: #FF4D4F">
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
</a-table>
</a-col>
</a-row>
<a-button type="primary" icon="plus" @click="addOutbound()" style="margin-bottom: 10px;">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
<a-button type="primary" @click="showWarp()" style="margin-bottom: 10px;">WARP</a-button>
<a-table :columns="outboundColumns" bordered
:row-key="r => r.key"
:data-source="outboundData"
:scroll="isMobile ? {} : { x: 200 }"
:pagination="false"
:indent-size="0"
:style="isMobile ? 'padding: 5px 5px' : 'margin-right: 1px;'">
<template slot="action" slot-scope="text, outbound, index">
[[ index+1 ]]
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editOutbound(index)">
<a-icon type="edit"></a-icon>
{{ i18n "edit" }}
</a-menu-item>
<a-menu-item @click="deleteOutbound(index)">
<span style="color: #FF4D4F">
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template slot="address" slot-scope="text, outbound, index">
<p style="margin: 0 5px;" v-for="addr in findOutboundAddress(outbound)">[[ addr ]]</p>
</template>
<template slot="protocol" slot-scope="text, outbound, index">
<a-tag style="margin:0;" color="purple">[[ outbound.protocol ]]</a-tag>
<template v-if="[Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)">
<a-tag style="margin:0;" color="blue">[[ outbound.streamSettings.network ]]</a-tag>
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='tls'" color="green">tls</a-tag>
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='reality'" color="green">reality</a-tag>
</template>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="tpl-4" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
<a-tab-pane key="tpl-4" tab='{{ i18n "pages.xray.outbound.reverse"}}' style="padding-top: 20px;" force-render="true">
<a-button type="primary" icon="plus" @click="addReverse()" style="margin-bottom: 10px;">{{ i18n "pages.xray.outbound.addReverse" }}</a-button>
<a-table :columns="reverseColumns" bordered
:row-key="r => r.key"
:data-source="reverseData"
:scroll="isMobile ? {} : { x: 200 }"
:pagination="false"
:indent-size="0"
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
<template slot="action" slot-scope="text, reverse, index">
[[ index+1 ]]
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editReverse(index)">
<a-icon type="edit"></a-icon>
{{ i18n "edit" }}
</a-menu-item>
<a-menu-item @click="deleteReverse(index)">
<span style="color: #FF4D4F">
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
<a-list-item-meta title='{{ i18n "pages.xray.Template"}}' description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta>
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" :size="isMobile ? 'small' : ''">
<a-radio-button value="xraySetting">{{ i18n "pages.xray.completeTemplate"}}</a-radio-button>
@@ -419,12 +431,13 @@
{{template "ruleModal"}}
{{template "outModal"}}
{{template "reverseModal"}}
{{template "warpModal"}}
<script>
const rulesColumns = [
{ title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } },
{ title: '{{ i18n "pages.xray.rules.source"}}', children: [
{ title: 'IP', dataIndex: "source", align: 'center', width: 20, ellipsis: true },
{ title: 'port', dataIndex: 'sourcePort', align: 'center', width: 10, ellipsis: true } ]},
{ title: 'Port', dataIndex: 'sourcePort', align: 'center', width: 10, ellipsis: true } ]},
{ title: '{{ i18n "pages.inbounds.network"}}', children: [
{ title: 'L4', dataIndex: 'network', align: 'center', width: 10 },
{ title: 'Protocol', dataIndex: 'protocol', align: 'center', width: 10, ellipsis: true },
@@ -435,7 +448,7 @@
{ title: 'Port', dataIndex: 'port', align: 'center', width: 10, ellipsis: true }]},
{ title: '{{ i18n "pages.xray.rules.inbound"}}', children: [
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 20, ellipsis: true },
{ title: 'User email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
{ title: '{{ i18n "pages.xray.rules.outbound"}}', dataIndex: 'outboundTag', align: 'center', width: 20 },
];
@@ -517,7 +530,7 @@
ips: {
local: ["geoip:private"],
cn: ["geoip:cn"],
ir: ["ext:geoip_IR.dat:ir","ext:geoip_IR.dat:arvancloud","ext:geoip_IR.dat:derakcloud","ext:geoip_IR.dat:iranserver"],
ir: ["ext:geoip_IR.dat:ir"],
ru: ["geoip:ru"],
},
domains: {
@@ -525,7 +538,9 @@
"geosite:category-ads-all",
"ext:geosite_IR.dat:category-ads-all"
],
openai: ["geosite:openai"],
google: ["geosite:google"],
spotify: ["geosite:spotify"],
netflix: ["geosite:netflix"],
cn: [
"geosite:cn",
@@ -707,6 +722,8 @@
break;
case Protocols.DNS:
return [o.settings.address + ':' + o.settings.port];
case Protocols.Wireguard:
return o.settings.peers.map(peer => peer.endpoint);
default:
return null;
}
@@ -782,17 +799,27 @@
confirm: (reverse, rules) => {
reverseModal.loading();
if(reverse.tag.length > 0){
oldtag = this.reverseData[index].tag;
this.deleteReverse(index);
oldData = this.reverseData[index];
newTemplateSettings = this.templateSettings;
if(newTemplateSettings.reverse == undefined) newTemplateSettings.reverse = {};
if(newTemplateSettings.reverse[reverse.type+'s'] == undefined) newTemplateSettings.reverse[reverse.type+'s'] = [];
newTemplateSettings.reverse[reverse.type+'s'].push({ tag: reverse.tag, domain: reverse.domain });
oldReverseIndex = newTemplateSettings.reverse[oldData.type+'s'].findIndex(rs => rs.tag == oldData.tag);
oldRuleIndex0 = oldRules.length>0 ? newTemplateSettings.routing.rules.findIndex(r => JSON.stringify(r) == JSON.stringify(oldRules[0])) : -1;
oldRuleIndex1 = oldRules.length==2 ? newTemplateSettings.routing.rules.findIndex(r => JSON.stringify(r) == JSON.stringify(oldRules[1])) : -1;
if(oldData.type == reverse.type){
newTemplateSettings.reverse[oldData.type + 's'][oldReverseIndex] = { tag: reverse.tag, domain: reverse.domain };
} else {
newTemplateSettings.reverse[oldData.type+'s'].splice(oldReverseIndex,1);
// delete empty object
if(newTemplateSettings.reverse[oldData.type+'s'].length == 0) Reflect.deleteProperty(newTemplateSettings.reverse, oldData.type+'s');
// add other type of reverse if it is not exist
if(!newTemplateSettings.reverse[reverse.type+'s']) newTemplateSettings.reverse[reverse.type+'s'] = [];
newTemplateSettings.reverse[reverse.type+'s'].push({ tag: reverse.tag, domain: reverse.domain });
}
this.templateSettings = newTemplateSettings;
// Adjust Rules
newRules = this.templateSettings.routing.rules.filter(r => r.outboundTag != oldtag && (r.inboundTag && !r.inboundTag.includes(oldtag)));
newRules.push(...rules)
newRules = this.templateSettings.routing.rules;
oldRuleIndex0 != -1 ? newRules[oldRuleIndex0] = rules[0] : newRules.push(rules[0]);
oldRuleIndex1 != -1 ? newRules[oldRuleIndex1] = rules[1] : newRules.push(rules[1]);
this.routingRuleSettings = JSON.stringify(newRules);
}
reverseModal.close();
@@ -807,10 +834,17 @@
realIndex = reverseTypeObj.findIndex(r => r.tag==oldData.tag && r.domain==oldData.domain);
newTemplateSettings.reverse[oldData.type+'s'].splice(realIndex,1);
// delete empty objects
if(reverseTypeObj.length == 0) Reflect.deleteProperty(newTemplateSettings.reverse, oldData.type+'s');
if(Object.keys(newTemplateSettings.reverse).length === 0) Reflect.deleteProperty(newTemplateSettings, 'reverse');
newRules = newTemplateSettings.routing.rules.filter(r => r.outboundTag != oldData.tag && (r.inboundTag && !r.inboundTag.includes(oldData.tag)));
// delete related routing rules
newRules = newTemplateSettings.routing.rules;
if(oldData.type == "bridge"){
newRules = newTemplateSettings.routing.rules.filter(r => !( r.inboundTag && r.inboundTag.length == 1 && r.inboundTag[0] == oldData.tag));
} else if(oldData.type == "portal"){
newRules = newTemplateSettings.routing.rules.filter(r => r.outboundTag != oldData.tag);
}
newTemplateSettings.routing.rules = newRules;
this.templateSettings = newTemplateSettings;
@@ -855,6 +889,9 @@
rules = this.templateSettings.routing.rules;
rules.splice(index,1);
this.routingRuleSettings = JSON.stringify(rules);
},
showWarp(){
warpModal.show();
}
},
async mounted() {
@@ -1030,6 +1067,14 @@
this.syncRulesWithOutbound("IPv4", this.ipv4Settings);
}
},
warpDomains: {
get: function () {
return this.templateRuleGetter({ outboundTag: "warp", property: "domain" });
},
set: function (newValue) {
this.templateRuleSetter({ outboundTag: "warp", property: "domain", data: newValue });
}
},
torrentSettings: {
get: function () {
return doAllItemsExist(this.settingsData.protocols.bittorrent, this.blockedProtocols);
@@ -1249,8 +1294,61 @@
}
}
},
WarpExist: {
get: function() {
return this.templateSettings ? this.templateSettings.outbounds.findIndex((o) => o.tag == "warp")>=0 : false;
},
},
GoogleWARPSettings: {
get: function () {
return doAllItemsExist(this.settingsData.domains.google, this.warpDomains);
},
set: function (newValue) {
if (newValue) {
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.google];
} else {
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.google.includes(data));
}
},
},
OpenAIWARPSettings: {
get: function () {
return doAllItemsExist(this.settingsData.domains.openai, this.warpDomains);
},
set: function (newValue) {
if (newValue) {
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.openai];
} else {
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.openai.includes(data));
}
},
},
NetflixWARPSettings: {
get: function () {
return doAllItemsExist(this.settingsData.domains.netflix, this.warpDomains);
},
set: function (newValue) {
if (newValue) {
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.netflix];
} else {
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.netflix.includes(data));
}
},
},
SpotifyWARPSettings: {
get: function () {
return doAllItemsExist(this.settingsData.domains.spotify, this.warpDomains);
},
set: function (newValue) {
if (newValue) {
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.spotify];
} else {
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.spotify.includes(data));
}
},
},
},
});
</script>
</body>
</html>
</html>

View File

@@ -20,7 +20,7 @@
<a-input v-model.trim="ruleModal.rule.source"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">Source Port
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
@@ -32,12 +32,12 @@
</a-form-item>
<a-form-item label='Network'>
<a-select v-model="ruleModal.rule.network" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="x in ['','tcp','tdp','tcp,udp']" :value="x">[[ x ]]</a-select-option>
<a-select-option v-for="x in ['','tcp','udp','tcp,udp']" :value="x">[[ x ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Protocol'>
<a-select v-model="ruleModal.rule.protocol" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="x in ['','http','tls','bittorrent']" :value="x">[[ x ]]</a-select-option>
<a-select v-model="ruleModal.rule.protocol" mode="multiple" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="x in ['http','tls','bittorrent']" :value="x">[[ x ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='Attributes'>
@@ -75,6 +75,17 @@
</template>
<a-input v-model.trim="ruleModal.rule.domain"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>
<template slot="title">
<span>{{ i18n "pages.xray.rules.useComma" }}</span>
</template>
User <a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input v-model.trim="ruleModal.rule.user"></a-input>
</a-form-item>
<a-form-item>
<template slot="label">
<a-tooltip>

View File

@@ -55,6 +55,7 @@ var defaultValueMap = map[string]string{
"subEncrypt": "true",
"subShowInfo": "false",
"subURI": "",
"warp": "",
}
type SettingService struct {
@@ -397,6 +398,13 @@ func (s *SettingService) GetSubURI() (string, error) {
return s.getString("subURI")
}
func (s *SettingService) GetWarp() (string, error) {
return s.getString("warp")
}
func (s *SettingService) SetWarp(data string) error {
return s.setString("warp", data)
}
func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
if err := allSetting.CheckValid(); err != nil {
return err

View File

@@ -1,8 +1,13 @@
package service
import (
"bytes"
_ "embed"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
"x-ui/util/common"
"x-ui/xray"
)
@@ -26,3 +31,142 @@ func (s *XraySettingService) CheckXrayConfig(XrayTemplateConfig string) error {
}
return nil
}
func (s *XraySettingService) GetWarpData() (string, error) {
warp, err := s.SettingService.GetWarp()
if err != nil {
return "", err
}
return warp, nil
}
func (s *XraySettingService) GetWarpConfig() (string, error) {
var warpData map[string]string
warp, err := s.SettingService.GetWarp()
if err != nil {
return "", err
}
err = json.Unmarshal([]byte(warp), &warpData)
if err != nil {
return "", err
}
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s", warpData["device_id"])
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
buffer := bytes.NewBuffer(make([]byte, 8192))
buffer.Reset()
_, err = buffer.ReadFrom(resp.Body)
if err != nil {
return "", err
}
return buffer.String(), nil
}
func (s *XraySettingService) RegWarp(secretKey string, publicKey string) (string, error) {
tos := time.Now().UTC().Format("2006-01-02T15:04:05.000Z")
hostName, _ := os.Hostname()
data := fmt.Sprintf(`{"key":"%s","tos":"%s","type": "PC","model": "x-ui", "name": "%s"}`, publicKey, tos, hostName)
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg")
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
if err != nil {
return "", err
}
req.Header.Add("CF-Client-Version", "a-7.21-0721")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
buffer := bytes.NewBuffer(make([]byte, 8192))
buffer.Reset()
_, err = buffer.ReadFrom(resp.Body)
if err != nil {
return "", err
}
var rspData map[string]interface{}
err = json.Unmarshal(buffer.Bytes(), &rspData)
if err != nil {
return "", err
}
deviceId := rspData["id"].(string)
token := rspData["token"].(string)
license, ok := rspData["account"].(map[string]interface{})["license"].(string)
if !ok {
fmt.Println("Error accessing license value.")
return "", err
}
warpData := fmt.Sprintf("{\n \"access_token\": \"%s\",\n \"device_id\": \"%s\",", token, deviceId)
warpData += fmt.Sprintf("\n \"license_key\": \"%s\",\n \"private_key\": \"%s\"\n}", license, secretKey)
s.SettingService.SetWarp(warpData)
result := fmt.Sprintf("{\n \"data\": %s,\n \"config\": %s\n}", warpData, buffer.String())
return result, nil
}
func (s *XraySettingService) SetWarpLicence(license string) (string, error) {
var warpData map[string]string
warp, err := s.SettingService.GetWarp()
if err != nil {
return "", err
}
err = json.Unmarshal([]byte(warp), &warpData)
if err != nil {
return "", err
}
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s/account", warpData["device_id"])
data := fmt.Sprintf(`{"license": "%s"}`, license)
req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(data)))
if err != nil {
return "", err
}
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
buffer := bytes.NewBuffer(make([]byte, 8192))
buffer.Reset()
_, err = buffer.ReadFrom(resp.Body)
if err != nil {
return "", err
}
warpData["license_key"] = license
newWarpData, err := json.MarshalIndent(warpData, "", " ")
if err != nil {
return "", err
}
s.SettingService.SetWarp(string(newWarpData))
println(string(newWarpData))
return string(newWarpData), nil
}

View File

@@ -1,6 +1,6 @@
"username" = "Username"
"password" = "Password"
"login" = "Login"
"login" = "Log In"
"confirm" = "Confirm"
"cancel" = "Cancel"
"close" = "Close"
@@ -8,7 +8,7 @@
"copied" = "Copied"
"download" = "Download"
"remark" = "Remark"
"enable" = "Enable"
"enable" = "Enabled"
"protocol" = "Protocol"
"search" = "Search"
"filter" = "Filter"
@@ -26,13 +26,13 @@
"edit" = "Edit"
"delete" = "Delete"
"reset" = "Reset"
"copySuccess" = "Copied successfully"
"copySuccess" = "Copied Successful"
"sure" = "Sure"
"encryption" = "Encryption"
"transmission" = "Transmission"
"host" = "Host"
"path" = "Path"
"camouflage" = "Camouflage"
"camouflage" = "Obfuscation"
"status" = "Status"
"enabled" = "Enabled"
"disabled" = "Disabled"
@@ -40,83 +40,83 @@
"depletingSoon" = "Depleting"
"offline" = "Offline"
"online" = "Online"
"domainName" = "Domain name"
"domainName" = "Domain Name"
"monitor" = "Listen IP"
"certificate" = "Certificate"
"fail" = " Fail"
"success" = " Success"
"getVersion" = "Get version"
"success" = " Successful"
"getVersion" = "Get Version"
"install" = "Install"
"clients" = "Clients"
"usage" = "Usage"
"remained" = "Remained"
"secAlertTitle" = "Security Alert"
"secAlertSsl" = "This connection is not secure; Please refrain from entering sensitive information until TLS is activated for data protection"
"secAlertSsl" = "THIS CONNECTION IS NOT SECURE. PLEASE AVOID ENTERING SENSITIVE INFORMATION UNTIL TLS IS ACTIVATED FOR DATA PROTECTION."
"security" = "Security"
[menu]
"dashboard" = "System Status"
"inbounds" = "Inbounds"
"settings" = "Panel Settings"
"xray" = "Xray Settings"
"logout" = "Logout"
"link" = "Other"
"dashboard" = "OVERVIEW"
"inbounds" = "INBOUNDS"
"settings" = "PANEL SETTINGS"
"xray" = "XRAY CONFIGS"
"logout" = "LOG OUT"
"link" = "Management"
[pages.login]
"title" = "Login"
"loginAgain" = "The login time limit has expired, please log in again"
"title" = "Welcome"
"loginAgain" = "Your session has expired, please log in again"
[pages.login.toasts]
"invalidFormData" = "Input data format is invalid."
"emptyUsername" = "Please enter username."
"emptyPassword" = "Please enter password."
"wrongUsernameOrPassword" = "Invalid username or password."
"invalidFormData" = "The input data format is invalid"
"emptyUsername" = "Username is required"
"emptyPassword" = "Password is required"
"wrongUsernameOrPassword" = "The username or password is incorrect"
"successLogin" = "Login"
[pages.index]
"title" = "System Status"
"memory" = "Memory"
"hard" = "Hard Disk"
"xrayStatus" = "Xray Status"
"title" = "Overview"
"memory" = "RAM"
"hard" = "Disk"
"xrayStatus" = "Status"
"stopXray" = "Stop"
"restartXray" = "Restart"
"xraySwitch" = "Switch Version"
"xraySwitchClick" = "Choose the version you want to switch to."
"xraySwitchClickDesk" = "Choose wisely, as older versions may not be compatible with current configurations."
"operationHours" = "Operation Hours"
"operationHoursDesc" = "System uptime: time since startup."
"xraySwitch" = "Change Xray Version"
"xraySwitchClick" = "Choose the version you want to switch."
"xraySwitchClickDesk" = "Choose carefully, as older versions may not be compatible with the current configurations."
"operationHours" = "Uptime"
"operationHoursDesc" = "Time since startup"
"systemLoad" = "System Load"
"connectionTcpCountDesc" = "Total TCP connections across all network cards."
"connectionUdpCountDesc" = "Total UDP connections across all network cards."
"upSpeed" = "Total upload speed for all network cards."
"downSpeed" = "Total download speed for all network cards."
"totalSent" = "Total upload traffic of all network cards since system startup."
"totalReceive" = "Total download data across all network cards since system startup."
"xraySwitchVersionDialog" = "Switch Xray Version"
"xraySwitchVersionDialogDesc" = "Are you sure you want to switch the Xray version to"
"connectionTcpCountDesc" = "Total TCP connections across all networks"
"connectionUdpCountDesc" = "Total UDP connections across all networks"
"upSpeed" = "Overall upload speed across all networks"
"downSpeed" = "Overall download speed across all networks"
"totalSent" = "Total traffic sent across all networks since OS startup"
"totalReceive" = "Total traffic received across all networks since OS startup"
"xraySwitchVersionDialog" = "Change Xray Version"
"xraySwitchVersionDialogDesc" = "Are you sure you want to change the Xray version to"
"dontRefresh" = "Installation is in progress, please do not refresh this page."
"logs" = "Logs"
"config" = "Config"
"backup" = "Backup & Restore"
"backupTitle" = "Backup & Restore Database"
"backupDescription" = "Remember to backup before importing a new database."
"exportDatabase" = "Download Database"
"importDatabase" = "Upload Database"
"backupDescription" = "It is recommended to make a backup before importing a new database."
"exportDatabase" = "Backup"
"importDatabase" = "Restore"
[pages.inbounds]
"title" = "Inbounds"
"totalDownUp" = "Total Uploads/Downloads"
"totalDownUp" = "Total Sent/Received"
"totalUsage" = "Total Usage"
"inboundCount" = "Number of Inbounds"
"inboundCount" = "Total Inbounds"
"operate" = "Menu"
"enable" = "Enable"
"enable" = "Enabled"
"remark" = "Remark"
"protocol" = "Protocol"
"port" = "Port"
"traffic" = "Traffic"
"details" = "Details"
"transportConfig" = "Transport Config"
"expireDate" = "Expire Date"
"expireDate" = "Expiry Date"
"resetTraffic" = "Reset Traffic"
"addInbound" = "Add Inbound"
"generalActions" = "General Actions"
@@ -128,16 +128,16 @@
"deleteClient" = "Delete Client"
"deleteClientContent" = "Are you sure you want to delete client?"
"resetTrafficContent" = "Are you sure you want to reset traffic?"
"copyLink" = "Copy Link"
"copyLink" = "Copy URL"
"address" = "Address"
"network" = "Network"
"destinationPort" = "Destination Port"
"targetAddress" = "Target Address"
"monitorDesc" = "Leave blank by default"
"meansNoLimit" = "Means No Limit"
"monitorDesc" = "Leave blank to listen on all IPs"
"meansNoLimit" = "Means no limit"
"totalFlow" = "Total Flow"
"leaveBlankToNeverExpire" = "Leave blank to never expire"
"noRecommendKeepDefault" = "No special requirements to keep the default"
"noRecommendKeepDefault" = "It is recommended to keep the default"
"certificatePath" = "File Path"
"certificateContent" = "File Content"
"publicKeyPath" = "Public Key Path"
@@ -146,40 +146,40 @@
"keyContent" = "Private Key Content"
"clickOnQRcode" = "Click on QR Code to Copy"
"client" = "Client"
"export" = "Export Links"
"export" = "Export All URLs"
"clone" = "Clone"
"cloneInbound" = "Clone"
"cloneInboundContent" = "All settings of this inbound, except for Port, Listening IP, and Clients, will be applied to the clone."
"cloneInboundContent" = "All settings for this inbound, except Port, Listening IP, and Clients, will be applied to the clone."
"cloneInboundOk" = "Clone"
"resetAllTraffic" = "Reset All Inbounds Traffic"
"resetAllTrafficTitle" = "Reset all inbounds traffic"
"resetAllTrafficContent" = "Are you sure you want to reset all inbounds traffic?"
"resetAllTrafficTitle" = "Reset All Inbounds Traffic"
"resetAllTrafficContent" = "Are you sure you want to reset the traffic of all inbounds?"
"resetInboundClientTraffics" = "Reset Clients Traffic"
"resetInboundClientTrafficTitle" = "Reset all clients traffic"
"resetInboundClientTrafficContent" = "Are you sure you want to reset all traffic for this inbound's clients?"
"resetInboundClientTrafficTitle" = "Reset Clients Traffic"
"resetInboundClientTrafficContent" = "Are you sure you want to reset the traffic of this inbound's clients?"
"resetAllClientTraffics" = "Reset All Clients Traffic"
"resetAllClientTrafficTitle" = "Reset all clients traffic"
"resetAllClientTrafficContent" = "Are you sure you want to reset all traffics for all clients?"
"resetAllClientTrafficTitle" = "Reset All Clients Traffic"
"resetAllClientTrafficContent" = "Are you sure you want to reset the traffic of all clients?"
"delDepletedClients" = "Delete Depleted Clients"
"delDepletedClientsTitle" = "Delete depleted clients"
"delDepletedClientsContent" = "Are you sure you want to delete all depleted clients?"
"delDepletedClientsTitle" = "Delete Depleted Clients"
"delDepletedClientsContent" = "Are you sure you want to delete all the depleted clients?"
"email" = "Email"
"emailDesc" = "Please provide a unique email address."
"setDefaultCert" = "Set cert from panel"
"telegramDesc" = "Use Telegram ID without @ or chat IDs ( you can get it here @userinfobot or use '/id' command in bot )"
"subscriptionDesc" = "You can find your sub link on Details, also you can use the same name for several configurations"
"info" = "Info"
"emailDesc" = "Please provide a unique email address"
"setDefaultCert" = "Set Cert from Panel"
"telegramDesc" = "Please provide Telegram or Chat ID(s) without using the '@'. (get it here @userinfobot) or (use '/id' command in the bot)"
"subscriptionDesc" = "To find your subscription URL, navigate to the 'Details'. Additionally, you can use the same name for several clients."
"info" = "Info"
"same" = "Same"
"inboundData" = "Inbound's data"
"copyToClipboard" = "Copy to clipboard"
"inboundData" = "Inbound's Data"
"copyToClipboard" = "Copy to Clipboard"
"import" = "Import"
"importInbound" = "Import an inbound"
"importInbound" = "Import an Inbound"
[pages.client]
"add" = "Add Client"
"edit" = "Edit Client"
"submitAdd" = "Add Client"
"submitEdit" = "Save changes"
"submitEdit" = "Save Changes"
"clientCount" = "Number of Clients"
"bulk" = "Add Bulk"
"method" = "Method"
@@ -187,177 +187,187 @@
"last" = "Last"
"prefix" = "Prefix"
"postfix" = "Postfix"
"delayedStart" = "Start after first use"
"expireDays" = "Expire days"
"days" = "day(s)"
"renew" = "Auto renew"
"renewDesc" = "Auto renew days after expiration. 0 = disable"
"delayedStart" = "Start after First Use"
"expireDays" = "Duration"
"days" = "Day(s)"
"renew" = "Auto Renew"
"renewDesc" = "Auto-renewal after expiration. (0 = disable)(unit: day)"
[pages.inbounds.toasts]
"obtain" = "Obtain"
[pages.inbounds.stream.general]
"requestHeader" = "Request header"
"requestHeader" = "Request Header"
"name" = "Name"
"value" = "Value"
[pages.inbounds.stream.tcp]
"requestVersion" = "Request version"
"requestMethod" = "Request method"
"requestPath" = "Request path"
"responseVersion" = "Response version"
"responseStatus" = "Response status"
"responseStatusDescription" = "Response status description"
"responseHeader" = "Response header"
"requestVersion" = "Request Version"
"requestMethod" = "Request Method"
"requestPath" = "Request Path"
"responseVersion" = "Response Version"
"responseStatus" = "Response Status"
"responseStatusDescription" = "Response Status Description"
"responseHeader" = "Response Header"
[pages.inbounds.stream.quic]
"encryption" = "Encryption"
[pages.settings]
"title" = "Settings"
"title" = "Panel Settings"
"save" = "Save"
"infoDesc" = "Every change made here needs to be saved. Please restart the panel for the changes to take effect."
"restartPanel" = "Restart Panel "
"restartPanelDesc" = "Are you sure you want to restart the panel? Click OK to restart after 3 seconds. If you cannot access the panel after restarting, please view the panel log information on the server."
"resetDefaultConfig" = "Reset to default config"
"panelConfig" = "Panel Configurations"
"userSettings" = "User Settings"
"TGBotSettings" = "Telegram Bot Settings"
"panelListeningIP" = "Panel Listening IP"
"panelListeningIPDesc" = "Leave blank by default to monitor all IPs."
"panelListeningDomain" = "Panel Listening Domain"
"panelListeningDomainDesc" = "Leave blank by default to monitor all domains and IPs"
"panelPort" = "Panel Port"
"panelPortDesc" = "Port number for serving the panel."
"publicKeyPath" = "Panel Certificate Public Key File Path"
"publicKeyPathDesc" = "Fill in an absolute path starting with '/'"
"privateKeyPath" = "Panel Certificate Private Key File Path"
"privateKeyPathDesc" = "Fill in an absolute path starting with '/'"
"panelUrlPath" = "Panel URL Root Path"
"panelUrlPathDesc" = "Must start with '/' and end with '/'"
"pageSize" = "Pagination size"
"pageSizeDesc" = "Define page size for inbounds table. Set 0 to disable"
"remarkModel" = "Remark Model and Seperation charachter"
"sampleRemark" = "Sample remark"
"restartPanel" = "Restart Panel"
"restartPanelDesc" = "Are you sure you want to restart the panel? If you are unable to access the panel after restarting, please check the logs in the terminal script"
"resetDefaultConfig" = "Reset to Default"
"panelConfig" = "Configuration"
"userSettings" = "Authentication"
"TGBotSettings" = "Telegram Bot"
"panelListeningIP" = "Listen IP"
"panelListeningIPDesc" = "The IP address for the web panel. (leave blank to listen on all IPs)"
"panelListeningDomain" = "Listen Domain"
"panelListeningDomainDesc" = "The domain name for the web panel. (leave blank to listen on all domains and IPs)"
"panelPort" = "Listen Port"
"panelPortDesc" = "The port number for the web panel. (must be an unused port)"
"publicKeyPath" = "Public Key Path"
"publicKeyPathDesc" = "The public key file path for the web panel. (begins with /)"
"privateKeyPath" = "Private Key Path"
"privateKeyPathDesc" = "The private key file path for the web panel. (begins with /)"
"panelUrlPath" = "URI Path"
"panelUrlPathDesc" = "The URI path for the web panel. (begins with / and concludes with /)"
"pageSize" = "Pagination Size"
"pageSizeDesc" = "Define page size for the inbounds table. (0 = disable)"
"remarkModel" = "Remark Model & Separation Character"
"sampleRemark" = "Sample Remark"
"oldUsername" = "Current Username"
"currentPassword" = "Current Password"
"newUsername" = "New Username"
"newPassword" = "New Password"
"telegramBotEnable" = "Enable Telegram bot"
"telegramBotEnableDesc" = "Your telegram bot will interact with the panel"
"telegramBotEnable" = "Enable Telegram Bot"
"telegramBotEnableDesc" = "Enables the Telegram bot."
"telegramToken" = "Telegram Token"
"telegramTokenDesc" = "The Token you have got from @BotFather"
"telegramChatId" = "Telegram Admin ChatIDs"
"telegramChatIdDesc" = "Multiple Chat IDs separated by comma. use @userinfobot or use '/id' command in bot to get your Chat IDs."
"telegramNotifyTime" = "Telegram bot notification time"
"telegramNotifyTimeDesc" = "Use Crontab timing format."
"telegramTokenDesc" = "The Telegram bot token obtained from '@BotFather'."
"telegramChatId" = "Admin Chat ID"
"telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (comma-separated)(use @userinfobot) or (use '/id' command in the bot)"
"telegramNotifyTime" = "Notification Time"
"telegramNotifyTimeDesc" = "The Telegram bot notification time set for periodic reports. (use the crontab time format)"
"tgNotifyBackup" = "Database Backup"
"tgNotifyBackupDesc" = "Send database backup file with report notification"
"tgNotifyBackupDesc" = "Send a database backup file with a report."
"tgNotifyLogin" = "Login Notification"
"tgNotifyLoginDesc" = "Displays the username, IP address, and time when someone tries to log into your panel."
"sessionMaxAge" = "Session maximum age"
"sessionMaxAgeDesc" = "The time that you can stay login (unit: minute)"
"expireTimeDiff" = "Expiration threshold for notification"
"expireTimeDiffDesc" = "Get notified about account expiration before the threshold (unit: day)"
"trafficDiff" = "Traffic threshold for notification"
"trafficDiffDesc" = "Get notified about traffic exhaustion before reaching the threshold (unit: GB)"
"tgNotifyCpu" = "CPU percentage alert threshold"
"tgNotifyCpuDesc" = "Receive notification if CPU usage exceeds this threshold (unit: %)"
"tgNotifyLoginDesc" = "Get notified about the username, IP address, and time whenever someone attempts to log into your web panel."
"sessionMaxAge" = "Session Duration"
"sessionMaxAgeDesc" = "The duration for which you can stay logged in. (unit: minute)"
"expireTimeDiff" = "Client Expiration Threshold Notification"
"expireTimeDiffDesc" = "Get notified about client expiration when reaching this threshold. (unit: day)"
"trafficDiff" = "Traffic Exhaustion Threshold Notification"
"trafficDiffDesc" = "Get notified about traffic exhaustion when reaching this threshold. (unit: GB)"
"tgNotifyCpu" = "CPU Load Threshold Notification"
"tgNotifyCpuDesc" = "Get notified if CPU usage exceeds this threshold. (unit: %)"
"timeZone" = "Time Zone"
"timeZoneDesc" = "Scheduled tasks run according to the time in this time zone."
"timeZoneDesc" = "Scheduled tasks run based on this time zone."
"subSettings" = "Subscription"
"subEnable" = "Enable service"
"subEnableDesc" = "Subscription feature with separate configuration"
"subListen" = "Listening IP"
"subListenDesc" = "Leave blank by default to monitor all IPs"
"subPort" = "Subscription Port"
"subPortDesc" = "Port number for serving the subscription service must be unused in server"
"subCertPath" = "Subscription Certificate Public Key File Path"
"subCertPathDesc" = "Fill in an absolute path starting with '/'"
"subKeyPath" = "Subscription Certificate Private Key File Path"
"subKeyPathDesc" = "Fill in an absolute path starting with '/'"
"subPath" = "Subscription URL Root Path"
"subPathDesc" = "Must start with '/' and end with '/'"
"subDomain" = "Listening Domain"
"subDomainDesc" = "Leave blank by default to monitor all domains and IPs"
"subUpdates" = "Subscription update intervals"
"subUpdatesDesc" = "Interval hours between updates in client application"
"subEncrypt" = "Encrypt configs"
"subEncryptDesc" = "Encrypt the returned configs in subscription"
"subShowInfo" = "Show usage info"
"subShowInfoDesc" = "Show remained traffic and date after config name"
"subEnable" = "Enable Subscription Service"
"subEnableDesc" = "Enables the subscription service."
"subListen" = "Listen IP"
"subListenDesc" = "The IP address for the subscription service. (leave blank to listen on all IPs)"
"subPort" = "Listen Port"
"subPortDesc" = "The port number for the subscription service. (must be an unused port)"
"subCertPath" = "Public Key Path"
"subCertPathDesc" = "The public key file path for the subscription service. (begins with /)"
"subKeyPath" = "Private Key Path"
"subKeyPathDesc" = "The private key file path for the subscription service. (begins with /)"
"subPath" = "URI Path"
"subPathDesc" = "The URI path for the subscription service. (begins with / and concludes with /)"
"subDomain" = "Listen Domain"
"subDomainDesc" = "The domain name for the subscription service. (leave blank to listen on all domains and IPs)"
"subUpdates" = "Update Intervals"
"subUpdatesDesc" = "The update intervals of the subscription URL in the client apps. (unit: hour)"
"subEncrypt" = "Encode"
"subEncryptDesc" = "The returned content of subscription service will be Base64 encoded."
"subShowInfo" = "Show Usage Info"
"subShowInfoDesc" = "The remaining traffic and date will be displayed in the client apps."
"subURI" = "Reverse Proxy URI"
"subURIDesc" = "Change base URI of subscription URL for using on behind of proxies"
"subURIDesc" = "The URI path of the subscription URL for use behind proxies."
[pages.settings.toasts]
"modifySettings" = "Modify Settings "
"getSettings" = "Get Settings "
"modifyUser" = "Modify User "
"originalUserPassIncorrect" = "Incorrect original username or password"
"userPassMustBeNotEmpty" = "New username and new password cannot be empty"
"modifySettings" = "Modify Settings"
"getSettings" = "Get Settings"
"modifyUser" = "Modify User"
"originalUserPassIncorrect" = "The current username or password is incorrect"
"userPassMustBeNotEmpty" = "The new username or password is required"
[pages.xray]
"title" = "Xray Settings"
"save" = "Save Settings"
"title" = "Xray Configs"
"save" = "Save"
"restart" = "Restart Xray"
"basicTemplate" = "Basic Template"
"advancedTemplate" = "Advanced Template"
"generalConfigs" = "General Configs"
"generalConfigsDesc" = "These options will provide general adjustments."
"blockConfigs" = "Blocking Configs"
"blockConfigsDesc" = "These options will prevent users from connecting to specific protocols and websites."
"blockCountryConfigs" = "Block Country Configs"
"blockCountryConfigsDesc" = "These options will prevent users from connecting to specific country domains."
"directCountryConfigs" = "Direct Country Configs"
"directCountryConfigsDesc" = "These options will connect users directly to specific country domains."
"ipv4Configs" = "IPv4 Configs"
"ipv4ConfigsDesc" = "These options will route to target domains only via IPv4."
"Template" = "Xray Configuration Template"
"TemplateDesc" = "Generate the final Xray configuration file based on this template."
"FreedomStrategy" = "Configure Strategy for Freedom Protocol"
"FreedomStrategyDesc" = "Set the output strategy of the network in the Freedom Protocol."
"RoutingStrategy" = "Configure Domains Routing Strategy"
"RoutingStrategyDesc" = "Set the overall routing strategy for DNS resolving."
"Torrent" = "Ban BitTorrent Usage"
"TorrentDesc" = "Change the configuration template to avoid using BitTorrent by users."
"PrivateIp" = "Ban Private IP Ranges to Connect"
"PrivateIpDesc" = "Change the configuration template to avoid connecting to private IP ranges."
"basicTemplate" = "Basic"
"advancedTemplate" = "Advanced"
"generalConfigs" = "General Strategy"
"generalConfigsDesc" = "These options will determine general strategy adjustments."
"blockConfigs" = "Protection Shield"
"blockConfigsDesc" = "These options will block traffic based on specific requested protocols and websites."
"blockCountryConfigs" = "Block Country"
"blockCountryConfigsDesc" = "These options will block traffic based on the specific requested country."
"directCountryConfigs" = "Direct Country"
"directCountryConfigsDesc" = "These options will directly forward traffic based on the specific requested country."
"ipv4Configs" = "IPv4 Routing"
"ipv4ConfigsDesc" = "These options will route requests to destination only via IPv4."
"warpConfigs" = "WARP Routing"
"warpConfigsDesc" = "WARP will route traffic to websites through Cloudflare servers."
"Template" = "Advanced Xray Configuration Template"
"TemplateDesc" = "The final Xray configuration file will be generated based on this template."
"FreedomStrategy" = "Freedom Protocol Strategy"
"FreedomStrategyDesc" = "Set the output strategy for the network in the Freedom Protocol."
"RoutingStrategy" = "Overall Routing Strategy"
"RoutingStrategyDesc" = "Set the overall traffic routing strategy for resolving all requests."
"Torrent" = "Block BitTorrent Protocol"
"TorrentDesc" = "Blocks BitTorrent protocol."
"PrivateIp" = "Block Connection to Private IPs"
"PrivateIpDesc" = "Blocks establishing connections to private IP ranges."
"Ads" = "Block Ads"
"AdsDesc" = "Change the configuration template to block ads"
"Family" = "Enable Family-Friendly Configuration"
"FamilyDesc" = "Avoid connecting to unsafe websites for family protection."
"IRIp" = "Disable connection to Iran IP ranges"
"IRIpDesc" = "Change the configuration template to avoid connecting to Iran IP ranges."
"IRDomain" = "Disable connection to Iran domains"
"IRDomainDesc" = "Change the configuration template to avoid connecting to Iran domains."
"ChinaIp" = "Disable connection to China IP ranges"
"ChinaIpDesc" = "Change the configuration template to avoid connecting to China IP ranges."
"ChinaDomain" = "Disable connection to China domains"
"ChinaDomainDesc" = "Change the configuration template to avoid connecting to China domains."
"RussiaIp" = "Disable connection to Russia IP ranges"
"RussiaIpDesc" = "Change the configuration template to avoid connecting to Russia IP ranges."
"RussiaDomain" = "Disable connection to Russia domains"
"RussiaDomainDesc" = "Change the configuration template to avoid connecting to Russia domains."
"DirectIRIp" = "Direct connection to Iran IP ranges"
"DirectIRIpDesc" = "Change the configuration template for direct connecting to Iran IP ranges."
"DirectIRDomain" = "Direct connection to Iran domains"
"DirectIRDomainDesc" = "Change the configuration template for direct connecting to Iran domains."
"DirectChinaIp" = "Direct connection to China IP ranges"
"DirectChinaIpDesc" = "Change the configuration template for direct connecting to China IP ranges."
"DirectChinaDomain" = "Direct connection to China domains"
"DirectChinaDomainDesc" = "Change the configuration template for direct connecting to China domains."
"DirectRussiaIp" = "Direct connection to Russia IP ranges"
"DirectRussiaIpDesc" = "Change the configuration template for direct connecting to Russia IP ranges."
"DirectRussiaDomain" = "Direct connection to Russia domains"
"DirectRussiaDomainDesc" = "Change the configuration template for direct connecting to Russia domains."
"GoogleIPv4" = "Use IPv4 for Google"
"GoogleIPv4Desc" = "Add routing for Google to connect with IPv4."
"NetflixIPv4" = "Use IPv4 for Netflix"
"NetflixIPv4Desc" = "Add routing for Netflix to connect with IPv4."
"AdsDesc" = "Blocks advertising websites."
"Family" = "Family Protection"
"FamilyDesc" = "Blocks adult content, and malware websites."
"IRIp" = "Block Connection to Iran IPs"
"IRIpDesc" = "Blocks establishing connections to Iran IP ranges."
"IRDomain" = "Block Connection to Iran Domains"
"IRDomainDesc" = "Blocks establishing connections to Iran domains."
"ChinaIp" = "Block Connection to China IPs"
"ChinaIpDesc" = "Blocks establishing connections to China IP ranges."
"ChinaDomain" = "Block Connection to China Domains"
"ChinaDomainDesc" = "Blocks establishing connections to China domains."
"RussiaIp" = "Block Connection to Russia IPs"
"RussiaIpDesc" = "Blocks establishing connections to Russia IP ranges."
"RussiaDomain" = "Block Connection to Russia Domains"
"RussiaDomainDesc" = "Blocks establishing connections to Russia domains."
"DirectIRIp" = "Direct Connection to Iran IPs"
"DirectIRIpDesc" = "Directly establishes connections to Iran IP ranges."
"DirectIRDomain" = "Direct Connection to Iran Domains"
"DirectIRDomainDesc" = "Directly establishes connections to Iran domains."
"DirectChinaIp" = "Direct Connection to China IPs"
"DirectChinaIpDesc" = "Directly establishes connections to China IP ranges."
"DirectChinaDomain" = "Direct Connection to China Domains"
"DirectChinaDomainDesc" = "Directly establishes connections to China domains."
"DirectRussiaIp" = "Direct Connection to Russia IPs"
"DirectRussiaIpDesc" = "Directly establishes connections to Russia IP ranges."
"DirectRussiaDomain" = "Direct Connection to Russia Domains"
"DirectRussiaDomainDesc" = "Directly establishes connections to Russia domains."
"GoogleIPv4" = "Google"
"GoogleIPv4Desc" = "Routes traffic to Google via IPv4."
"NetflixIPv4" = "Netflix"
"NetflixIPv4Desc" = "Routes traffic to Netflix via IPv4."
"GoogleWARP" = "Google"
"GoogleWARPDesc" = "Routes traffic to Google via WARP."
"OpenAIWARP" = "ChatGPT"
"OpenAIWARPDesc" = "Routes traffic to OpenAI (ChatGPT) via WARP."
"NetflixWARP" = "Netflix"
"NetflixWARPDesc" = "Routes traffic to Netflix via WARP."
"SpotifyWARP" = "Spotify"
"SpotifyWARPDesc" = "Routes traffic to Spotify via WARP."
"completeTemplate" = "All"
"Inbounds" = "Inbounds"
"Outbounds" = "Outbounds"
"Routings" = "Routing rules"
"Routings" = "Routing Rules"
"RoutingsDesc" = "The priority of each rule is important!"
[pages.xray.rules]
@@ -372,15 +382,15 @@
"info" = "Info"
"add" = "Add Rule"
"edit" = "Edit Rule"
"useComma" = "Comma separated items"
"useComma" = "Comma-separated items"
[pages.xray.outbound]
"addOutbound" = "Add outbound"
"addReverse" = "Add reverse"
"editOutbound" = "Edit outbound"
"editReverse" = "Edit reverse"
"addOutbound" = "Add Outbound"
"addReverse" = "Add Reverse"
"editOutbound" = "Edit Outbound"
"editReverse" = "Edit Reverse"
"tag" = "Tag"
"tagDesc" = "Unique tag"
"tagDesc" = "Unique Tag"
"address" = "Address"
"reverse" = "Reverse"
"domain" = "Domain"
@@ -389,6 +399,14 @@
"portal" = "Portal"
"intercon" = "Interconnection"
[pages.xray.wireguard]
"secretKey" = "Secret Key"
"publicKey" = "Public Key"
"allowedIPs" = "Allowed IPs"
"endpoint" = "Endpoint"
"psk" = "PreShared Key"
"domainStrategy" = "Domain Strategy"
[tgbot]
"noResult" = "❗ No result!"
"wentWrong" = "❌ Something went wrong!"
@@ -401,41 +419,41 @@
"clients" = "Clients"
[tgbot.commands]
"unknown" = "❗ Unknown command"
"unknown" = "❗Unknown command"
"pleaseChoose" = "👇 Please choose:\r\n"
"help" = "🤖 Welcome to this bot! It's designed to offer you specific data from the server, and it allows you to make modifications as needed.\r\n\r\n"
"help" = "🤖 Welcome to this bot! It's designed to provide you with specific data from the web panel and allows you to make modifications as needed.\r\n\r\n"
"start" = "👋 Hello <i>{{ .Firstname }}</i>.\r\n"
"welcome" = "🤖 Welcome to <b>{{ .Hostname }}</b> management bot.\r\n"
"status" = "✅ Bot is ok!"
"usage" = "❗ Please provide a text to search!"
"status" = "✅ Bot is OK!"
"usage" = "❗ Please provide a text to search!"
"getID" = "🆔 Your ID: <code>{{ .ID }}</code>"
"helpAdminCommands" = "Search for a client email:\r\n<code>/usage [Email]</code>\r\n \r\nSearch for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>"
"helpClientCommands" = "To search for statistics, just use the following command:\r\n \r\n<code>/usage [UUID|Password]</code>\r\n \r\nUse UUID for vmess/vless and Password for Trojan."
"helpAdminCommands" = "Search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nSearch for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>"
"helpClientCommands" = "To search for statistics, simply use the following command:\r\n\r\n<code>/usage [UUID|Password]</code>\r\n\r\nUse UUID for VMess/VLESS and password for Trojan/Shadowsocks."
[tgbot.messages]
"cpuThreshold" = "🔴 The CPU usage {{ .Percent }}% is more than threshold {{ .Threshold }}%"
"loginSuccess" = "✅ Successfully logged-in to the panel.\r\n"
"loginFailed" = "❗ Login to the panel failed.\r\n"
"report" = "🕰 Scheduled Reports: {{ .RunTime }}\r\n"
"datetime" = "⏰ Date-Time: {{ .DateTime }}\r\n"
"hostname" = "💻 Hostname: {{ .Hostname }}\r\n"
"version" = "🚀 X-UI Version: {{ .Version }}\r\n"
"cpuThreshold" = "🔴 CPU load {{ .Percent }}% = CPU load {{ .Percent }}% is more than the threshold of {{ .Threshold }}%"
"loginSuccess" = "✅ Logged in to the web panel successfully.\r\n"
"loginFailed" = "❗Log in to the web panel failed.\r\n"
"report" = "🕰 Scheduled reports: {{ .RunTime }}\r\n"
"datetime" = "⏰ Date&Time: {{ .DateTime }}\r\n"
"hostname" = "💻 Host: {{ .Hostname }}\r\n"
"version" = "🚀 X-UI: {{ .Version }}\r\n"
"ipv6" = "🌐 IPv6: {{ .IPv6 }}\r\n"
"ipv4" = "🌐 IPv4: {{ .IPv4 }}\r\n"
"ip" = "🌐 IP: {{ .IP }}\r\n"
"serverUpTime" = "⏳ Server Uptime: {{ .UpTime }} {{ .Unit }}\r\n"
"serverLoad" = "📈 Server Load: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
"serverMemory" = "📋 Server Memory: {{ .Current }}/{{ .Total }}\r\n"
"tcpCount" = "🔹 TcpCount: {{ .Count }}\r\n"
"udpCount" = "🔸 UdpCount: {{ .Count }}\r\n"
"serverUpTime" = "⏳ Uptime: {{ .UpTime }} {{ .Unit }}\r\n"
"serverLoad" = "📈 System load: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
"serverMemory" = "📋 RAM: {{ .Current }}/{{ .Total }}\r\n"
"tcpCount" = "🔹 TCP: {{ .Count }}\r\n"
"udpCount" = "🔸 UDP: {{ .Count }}\r\n"
"traffic" = "🚦 Traffic: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
"xrayStatus" = " Xray Status: {{ .State }}\r\n"
"username" = "👤 Username: {{ .Username }}\r\n"
"xrayStatus" = " Xray status: {{ .State }}\r\n"
"username" = "👤 Username: {{ .Username }}\r\n"
"time" = "⏰ Time: {{ .Time }}\r\n"
"inbound" = "📍 Inbound: {{ .Remark }}\r\n"
"port" = "🔌 Port: {{ .Port }}\r\n"
"expire" = "📅 Expire Date: {{ .DateTime }}\r\n \r\n"
"expireIn" = "📅 Expire In: {{ .Time }}\r\n \r\n"
"expire" = "📅 Expire date: {{ .DateTime }}\r\n \r\n"
"expireIn" = "📅 Expire in: {{ .Time }}\r\n \r\n"
"active" = "💡 Active: {{ .Enable }}\r\n"
"online" = "🌐 Connection status: {{ .Status }}\r\n"
"email" = "📧 Email: {{ .Email }}\r\n"
@@ -444,10 +462,10 @@
"total" = "🔄 Total: {{ .UpDown }} / {{ .Total }}\r\n"
"exhaustedMsg" = "🚨 Exhausted {{ .Type }}:\r\n"
"exhaustedCount" = "🚨 Exhausted {{ .Type }} count:\r\n"
"onlinesCount" = "🌐 Online clients count: {{ .Count }}\r\n"
"onlinesCount" = "🌐 Online clients: {{ .Count }}\r\n"
"disabled" = "🛑 Disabled: {{ .Disabled }}\r\n"
"depleteSoon" = "🔜 Deplete soon: {{ .Deplete }}\r\n \r\n"
"backupTime" = "🗄 Backup Time: {{ .Time }}\r\n"
"backupTime" = "🗄 Backup time: {{ .Time }}\r\n"
"yes" = "✅ Yes"
"no" = "❌ No"
@@ -455,12 +473,12 @@
"dbBackup" = "Get DB Backup"
"serverUsage" = "Server Usage"
"getInbounds" = "Get Inbounds"
"depleteSoon" = "Deplete soon"
"depleteSoon" = "Deplete Soon"
"clientUsage" = "Get Usage"
"onlines" = "Online Clients"
"commands" = "Commands"
[tgbot.answers]
"getInboundsFailed" = "❌ Failed to get inbounds"
"askToAddUser" = "Your configuration is not found!\r\nYou should configure your telegram username and ask your Admin to add it to your configuration."
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram username in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>"
"askToAddUser" = "Your configuration is not found!\r\nYou should configure your Telegram username and ask your Admin to add it to your configuration(s)."
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your Telegram username in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>"

View File

@@ -1,5 +1,5 @@
"username" = "نام کاربری"
"password" = "رمز عبور"
"username" = "نامکاربری"
"password" = "رمزعبور"
"login" = "ورود"
"confirm" = "تایید"
"cancel" = "انصراف"
@@ -12,7 +12,7 @@
"protocol" = "پروتکل"
"search" = "جستجو"
"filter" = "فیلتر"
"loading" = "در حال بروزرسانی..."
"loading" = "...در حال بارگذاری"
"second" = "ثانیه"
"minute" = "دقیقه"
"hour" = "ساعت"
@@ -21,93 +21,93 @@
"indefinite" = "نامحدود"
"unlimited" = "نامحدود"
"none" = "هیچ"
"qrCode" = "QR کد"
"qrCode" = "QRکد"
"info" = "اطلاعات بیشتر"
"edit" = "ویرایش"
"delete" = "حذف"
"reset" = "ریست"
"copySuccess" = "با موفقیت کپی شد"
"copySuccess" = "باموفقیت کپیشد"
"sure" = "مطمئن"
"encryption" = "رمزگذاری"
"transmission" = "راه اتصال"
"transmission" = "راهاتصال"
"host" = "آدرس"
"path" = "مسیر"
"camouflage" = "استتار"
"camouflage" = "مبهم‌سازی"
"status" = "وضعیت"
"enabled" = "فعال"
"disabled" = "غیرفعال"
"depleted" = "منقضی"
"depletingSoon" = "در حال انقضا"
"depletingSoon" = "درحالانقضا"
"offline" = "آفلاین"
"online" = "آنلاین"
"domainName" = "آدرس دامنه"
"monitor" = "آی پی اتصال"
"certificate" = "گواهی دیجیتال"
"fail" = "خطا"
"monitor" = "آیپی اتصال"
"certificate" = "گواهی"
"fail" = "ناموفق"
"success" = " موفق"
"getVersion" = "دریافت ورژن"
"getVersion" = "دریافت نسخه"
"install" = "نصب"
"clients" = "کاربران"
"usage" = "استفاده"
"remained" = "باقیمانده"
"secAlertTitle" = "هشدار امنیتی"
"secAlertSsl" = "این اتصال امن نیست؛ لطفا تا زمانی که تی‌ال‌اس برای حفاظت از داده ها فعال نشده است از وارد کردن اطلاعات حساس خودداری کنید"
"remained" = "باقیمانده"
"secAlertTitle" = "هشدارامنیتی"
"secAlertSsl" = "ایناتصالامن نیست. لطفا تازمانیکه تی‌ال‌اس برای محافظت از دادهها فعال نشدهاست، از وارد کردن اطلاعات حساس خودداریکنید"
"security" = "امنیت"
[menu]
"dashboard" = "وضعیت سیستم"
"inbounds" = "سرویس ها"
"dashboard" = "نمای کلی"
"inbounds" = "ورودی‌ها"
"settings" = "تنظیمات پنل"
"xray" = "الگوی ایکس‌ری"
"xray" = "پیکربندی ایکس‌ری"
"logout" = "خروج"
"link" = "دیگر"
"link" = "مدیریت"
[pages.login]
"title" = "ورود به سیستم"
"loginAgain" = "مدت زمان استفاده به اتمام رسیده ، لطفا دوباره وارد شوید"
"title" = "خوش‌آمدید"
"loginAgain" = "مدت زمان استفاده بهاتمامرسیده، لطفا دوباره وارد شوید"
[pages.login.toasts]
"invalidFormData" = "اطلاعات وارد شده به صورت درست وارد نشده است"
"emptyUsername" = "نام کاربری خالی میباشد"
"emptyPassword" = "رمز عبور خالی میباشد"
"wrongUsernameOrPassword" = "نام کاربری و رمز عبور اشتباه میباشد"
"successLogin" = "خوش آمدید"
"invalidFormData" = "اطلاعات به‌درستی وارد نشدهاست"
"emptyUsername" = "لطفا یک نامکاربری وارد کنید‌"
"emptyPassword" = "لطفا یک رمزعبور وارد کنید"
"wrongUsernameOrPassword" = "نامکاربری یا رمزعبوراشتباه‌است"
"successLogin" = "ورود"
[pages.index]
"title" = "وضعیت سیستم"
"memory" = "حافظه رم"
"hard" = "حافظه دیسک"
"xrayStatus" = "وضعیت Xray"
"title" = "نمای کلی"
"memory" = "RAM"
"hard" = "Disk"
"xrayStatus" = "وضعیت‌ایکس‌ری"
"stopXray" = "توقف"
"restartXray" = "شروع مجدد"
"xraySwitch" = "تغییر ورژن"
"xraySwitchClick" = "ورژن مورد نظر را انتخاب کنید"
"xraySwitchClickDesk" = "لطفا با دقت انتخاب کنید ، در صورت انتخاب اشتباه امکان قطعی سیستم وجود دارد "
"operationHours" = "مدت فعالیت"
"operationHoursDesc" = "مدت فعالیت سیستم بعد از روشن شدن"
"systemLoad" = "بار روی سیستم"
"connectionTcpCountDesc" = "مجموع اتصالات TCP در تمام کارت های شبکه"
"connectionUdpCountDesc" = "مجموع اتصالات UDP در تمام کارت های شبکه"
"upSpeed" = "سرعت آپلود در حال حاضر سیستم"
"downSpeed" = "سرعت دانلود در حال حاضر سیستم"
"totalSent" = "جمع کل ترافیک آپلود مصرفی"
"totalReceive" = "جمع کل ترافیک دانلود مصرفی"
"xraySwitchVersionDialog" = "تغییر ورژن Xray"
"xraySwitchVersionDialogDesc" = "آیا از تغییر ورژن مطمئن هستین"
"dontRefresh" = "در حال نصب ، لطفا رفرش نکنید "
"logs" = "گزارش ها"
"config" = "تنظیمات"
"backup" = "پشتیبان گیری"
"backupTitle" = "پشتیبان گیری دیتابیس"
"backupDescription" = "به یاد داشته باشید که قبل از وارد کردن یک دیتابیس جدید، نسخه پشتیبان تهیه کنید"
"exportDatabase" = "دانلود دیتابیس"
"importDatabase" = "آپلود دیتابیس"
"restartXray" = "شروعمجدد"
"xraySwitch" = "تغییر‌نسخه"
"xraySwitchClick" = سخه‌ مورد نظر را انتخاب کنید"
"xraySwitchClickDesk" = "لطفا بادقت انتخاب کنید. درصورت انتخاب نسخه قدیمی‌تر، امکان ناهماهنگی با پیکربندی فعلی وجود دارد"
"operationHours" = "مدت‌کارکرد"
"operationHoursDesc" = "مدت فعالیت سیستم‌عامل پس‌از شروع به‌کار"
"systemLoad" = "بارسیستم"
"connectionTcpCountDesc" = "در تمام‌شبکه‌ها TCP مجموع‌اتصالات"
"connectionUdpCountDesc" = "در تمام‌شبکه‌ها UDP مجموع‌اتصالات"
"upSpeed" = "سرعت کلی آپلود در تمام‌شبکه‌ها"
"downSpeed" = "سرعت کلی دانلود در تمام‌شبکه‌ها"
"totalSent" = "مجموع ترافیک ارسال‌‌شده پس‌از شروع‌به‌کار سیستم‌عامل"
"totalReceive" = "مجموع ترافیک دریافت‌شده پس‌از شروع‌به‌کار سیستم‌عامل"
"xraySwitchVersionDialog" = "تغییرنسخه‌ایکس‌ری"
"xraySwitchVersionDialogDesc" = "آیا از تغییر نسخه‌ مطمئن هستید؟"
"dontRefresh" = "در حال نصب، لطفا صفحه را رفرش نکنید"
"logs" = "گزارشها"
"config" = "پیکربندی"
"backup" = "پشتیبانگیری"
"backupTitle" = "پشتیبانگیری دیتابیس"
"backupDescription" = "توصیه‌می‌شود قبلاز واردکردن یک دیتابیس جدید، نسخه پشتیبان تهیه کنید"
"exportDatabase" = "پشتیبان‌گیری"
"importDatabase" = "بازگرداندن"
[pages.inbounds]
"title" = "کاربران"
"totalDownUp" = "جمع آپلود/دانلود"
"totalUsage" = "جمع کل"
"inboundCount" = "تعداد سرویس ها"
"totalDownUp" = "دریافت/ارسال کل"
"totalUsage" = "‌‌‌مصرف کل"
"inboundCount" = "کل ورودی‌ها"
"operate" = "عملیات"
"enable" = "فعال"
"remark" = "نام"
@@ -118,61 +118,61 @@
"transportConfig" = "نحوه اتصال"
"expireDate" = "تاریخ انقضا"
"resetTraffic" = "ریست ترافیک"
"addInbound" = "اضافه کردن سرویس"
"addInbound" = "افزودن ورودی"
"generalActions" = "عملیات کلی"
"create" = "اضافه کردن"
"create" = "افزودن"
"update" = "ویرایش"
"modifyInbound" = "ویرایش سرویس"
"deleteInbound" = "حذف سرویس"
"deleteInboundContent" = "آیا مطمئن به حذف سرویس هستید ؟"
"modifyInbound" = "ویرایش ورودی"
"deleteInbound" = "حذف ورودی"
"deleteInboundContent" = "آیا مطمئن به حذف ورودی هستید؟"
"deleteClient" = "حذف کاربر"
"deleteClientContent" = "آیا مطمئن به حذف کاربر هستید ؟"
"resetTrafficContent" = "آیا مطمئن به ریست ترافیک هستید ؟"
"deleteClientContent" = "آیا مطمئن به حذف کاربر هستید؟"
"resetTrafficContent" = "آیا مطمئن به ریست ترافیک هستید؟"
"copyLink" = "کپی لینک"
"address" = "آدرس"
"network" = "شبکه"
"destinationPort" = "پورت مقصد"
"targetAddress" = "آدرس مقصد"
"monitorDesc" = "به طور پیش فرض خالی بگذارید"
"meansNoLimit" = "یعنی بدون محدودیت"
"totalFlow" = "کل ترافیک"
"leaveBlankToNeverExpire" = "خالی بگذارید تا هرگز منقضی نشود"
"noRecommendKeepDefault" = "توصیه می شود به عنوان پیش فرض حفظ شود"
"monitorDesc" = "بهطور پیشفرض خالیبگذارید"
"meansNoLimit" = "یعنیبدونمحدودیت"
"totalFlow" = "ترافیک کل"
"leaveBlankToNeverExpire" = "برای منقضینشدن خالی‌بگذارید"
"noRecommendKeepDefault" = "توصیهمیشود به‌طور پیشفرض حفظشود"
"certificatePath" = "مسیر فایل"
"certificateContent" = "محتوای فایل"
"publicKeyPath" = "مسیر کلید عمومی"
"publicKeyContent" = "محتوای کلید عمومی"
"keyPath" = "مسیر کلید خصوصی"
"keyContent" = "محتوای کلید خصوصی"
"clickOnQRcode" = "برای کپی بر روی کد تصویری کلیک کنید"
"clickOnQRcode" = "برای کپی بر روی کدتصویری کلیک کنید"
"client" = "کاربر"
"export" = "استخراج لینک‌ها"
"clone" = "شبیه سازی"
"cloneInbound" = "شبیه‌سازی سرویس"
"cloneInboundContent" = "همه موارد این ورودی بجز پورت ، ای پی و کلاینت ها شبیه سازی خواهند شد"
"resetAllTraffic" = "ریست ترافیک کل سرویس ها"
"resetAllTrafficTitle" = "ریست ترافیک کل سرویس ها"
"resetAllTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک سرویس ها را ریست کنید؟"
"clone" = "شبیهسازی"
"cloneInbound" = "شبیه‌سازی ورودی"
"cloneInboundContent" = "همه موارد این ورودی بجز پورت، آی‌پی و کاربر‌ها شبیهسازی خواهند شد"
"resetAllTraffic" = "ریست ترافیک کل ورودی‌ها"
"resetAllTrafficTitle" = "ریست ترافیک کل ورودی‌ها"
"resetAllTrafficContent" = "آیا مطمئن به ریست ترافیک تمام ورودی‌ها هستید؟"
"resetInboundClientTraffics" = "ریست ترافیک کاربران"
"resetInboundClientTrafficTitle" = "ریست ترافیک کل کاربران"
"resetInboundClientTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک کاربران این سرویس را ریست کنید؟"
"resetAllClientTraffics" = "ریست ترافیک کاربران"
"resetInboundClientTrafficTitle" = "ریست ترافیک کاربران"
"resetInboundClientTrafficContent" = "آیا مطمئن به ریست ترافیک تمام کاربران این ورودی هستید؟"
"resetAllClientTraffics" = "ریست ترافیک کل کاربران"
"resetAllClientTrafficTitle" = "ریست ترافیک کل کاربران"
"resetAllClientTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک کاربران را ریست کنید؟"
"resetAllClientTrafficContent" = "آیا مطمئن به ریست ترافیک تمام کاربران هستید؟"
"delDepletedClients" = "حذف کاربران منقضی"
"delDepletedClientsTitle" = "حذف کاربران منقضی"
"delDepletedClientsContent" = "آیا مطمئن هستید مه میخواهید تمامی کاربران منقضی شده را حذف کنید؟"
"delDepletedClientsContent" = "آیا مطمئن به حذف تمام کاربران منقضیشده ‌هستید؟"
"email" = "ایمیل"
"emailDesc" = "ایمیل باید کاملا منحصر به فرد باشد"
"emailDesc" = "باید یک ایمیل یکتا باشد"
"setDefaultCert" = "استفاده از گواهی پنل"
"telegramDesc" = "از آیدی تلگرام بدون @ یا آیدی چت استفاده کنید (می توانید آن را از اینجا دریافت کنید @userinfobot یا در ربات دستور '/id' را وارد کنید)"
"subscriptionDesc" = "می توانید ساب لینک خود را در جزئیات پیدا کنید، همچنین می توانید از همین نام برای چندین کانفیگ استفاده کنید"
"telegramDesc" = " استفاده کنید'/id'یااز دستور @userinfobot آنرا اینجا دریافت کنید .از آی‌دی(های) چت تلگرام بدون '@' استفاده کنید"
"subscriptionDesc" = "شما میتوانید لینک سابسکربپشن خودرا در 'جزئیات' پیدا کنید، همچنین میتوانید از همین نام برای چندین کاربر استفادهکنید"
"info" = "اطلاعات"
"same" = "همسان"
"inboundData" = "داده‌های سرویس"
"inboundData" = "داده‌های ورودی"
"copyToClipboard" = "کپی در حافظه"
"import" = ارد کردن"
"importInbound" = ارد کردن یک سرویس"
"import" = "افزودن"
"importInbound" = "افزودن یک ورودی"
[pages.client]
"add" = "کاربر جدید"
@@ -180,20 +180,20 @@
"submitAdd" = "اضافه کردن"
"submitEdit" = "ذخیره تغییرات"
"clientCount" = "تعداد کاربران"
"bulk" = "انبوه سازی"
"bulk" = "انبوهسازی"
"method" = "روش"
"first" = "از"
"last" = "تا"
"prefix" = "پیشوند"
"postfix" = "پسوند"
"delayedStart" = "شروع بعد از اولین استفاده"
"expireDays" = "روزهای اعتبار"
"delayedStart" = "شروع‌پس‌ازاولیناستفاده"
"expireDays" = "مدت زمان"
"days" = "(روز)"
"renew" = "تمدید خودکار"
"renewDesc" = "روزهای تمدید خودکار پس از انقضا. 0 = غیرفعال"
"renewDesc" = "تمدید خودکار پساز انقضا. 0 = غیرفعال - واحد: روز"
[pages.inbounds.toasts]
"obtain" = "Obtain"
"obtain" = "فراهم‌سازی"
[pages.inbounds.stream.general]
"requestHeader" = "درخواست سربرگ"
@@ -201,10 +201,10 @@
"value" = "مقدار"
[pages.inbounds.stream.tcp]
"requestVersion" = "ورژن درخواست"
"requestVersion" = سخه درخواست"
"requestMethod" = "متد درخواست"
"requestPath" = "مسیر درخواست"
"responseVersion" = "ورژن پاسخ"
"responseVersion" = سخه پاسخ"
"responseStatus" = "وضعیت پاسخ"
"responseStatusDescription" = "توضیحات وضعیت پاسخ"
"responseHeader" = "سربرگ پاسخ"
@@ -213,151 +213,161 @@
"encryption" = "رمزنگاری"
[pages.settings]
"title" = "تنظیمات"
"title" = "تنظیمات پنل"
"save" = "ذخیره"
"infoDesc" = "برای اعمال تغییرات در این بخش باید پس از ذخیره کردن، پنل را ریستارت کنید"
"restartPanel" = "ریستارت پنل"
"restartPanelDesc" = "آیا مطمئن هستید که می خواهید پنل را دوباره راه اندازی کنید؟ برای راه اندازی مجدد روی OK کلیک کنید. اگر بعد از 3 ثانیه نمی توانید به پنل دسترسی پیدا کنید، لطفاً برای مشاهده اطلاعات گزارش پانل به سرور برگردید"
"resetDefaultConfig" = "برگشت به تنظیمات پیشفرض"
"panelConfig" = "تنظیمات پنل"
"userSettings" = "تنظیمات مدیر"
"TGBotSettings" = "تنظیمات ربات تلگرام"
"panelListeningIP" = "محدودیت آی پی پنل"
"panelListeningIPDesc" = "برای استفاده از تمام آی‌پیها به طور پیش فرض خالی بگذارید"
"panelListeningDomain" = "محدودیت دامین پنل"
"panelListeningDomainDesc" = "برای استفاده از تمام دامنه‌ها و آی‌پی‌ها به طور پیش فرض خالی بگذارید"
"panelPort" = "پورت پنل"
"panelPortDesc" = "پورت مورد استفاده برای نمایش این پنل"
"publicKeyPath" = "مسیر فایل گواهی کلید عمومی پنل"
"publicKeyPathDesc" = "باید یک مسیر مطلق باشد که با / شروع می شود "
"privateKeyPath" = "مسیر فایل گواهی کلید خصوصی پنل"
"privateKeyPathDesc" = "باید یک مسیر مطلق باشد که با / شروع می شود "
"panelUrlPath" = "آدرس روت پنل"
"panelUrlPathDesc" = "باید با '/' شروع شود و با '/' تمام شود"
"restartPanelDesc" = "آیا مطمئن به ریستارت پنل هستید؟ اگر پس‌از ریستارت نمیتوانید به پنل دسترسی پیدا کنید، لطفاً گزارش‌های موجود در اسکریپت پنل را بررسی کنید"
"resetDefaultConfig" = "برگشت به پیشفرض"
"panelConfig" = "پیکربندی"
"userSettings" = "احرازهویت"
"TGBotSettings" = "ربات تلگرام"
"panelListeningIP" = "آدرس آیپی"
"panelListeningIPDesc" = "آدرس آی‌پی برای وب پنل. برای گوش‌دادن به‌تمام آی‌پیها خالیبگذارید"
"panelListeningDomain" = "نام دامنه"
"panelListeningDomainDesc" = "آدرس دامنه برای وب پنل. برای گوش دادن به‌تمام دامنه‌ها و آی‌پی‌ها خالیبگذارید"
"panelPort" = "پورت"
"panelPortDesc" = "شماره پورت برای وب پنل. باید پورت استفاده نشده‌باشد"
"publicKeyPath" = "مسیر کلید عمومی"
"publicKeyPathDesc" = "مسیر فایل کلیدعمومی برای وب پنل. با '/' شروعمیشود"
"privateKeyPath" = "مسیر کلید خصوصی"
"privateKeyPathDesc" = "مسیر فایل کلیدخصوصی برای وب پنل. با '/' شروعمیشود"
"panelUrlPath" = "URI مسیر"
"panelUrlPathDesc" = رای وب پنل. با '/' شروع و با '/' خاتمه‌ می‌یابد URI مسیر"
"pageSize" = "اندازه صفحه بندی جدول"
"pageSizeDesc" = "اندازه صفحه را برای جدول سرویس ها تعریف کنید. 0: غیرفعال"
"remarkModel" = "نام کانفیگ و جداکننده"
"sampleRemark" = "نمونه نام"
"oldUsername" = "نام کاربری فعلی"
"currentPassword" = "رمز عبور فعلی"
"newUsername" = "نام کاربری جدید"
"newPassword" = "رمز عبور جدید"
"telegramBotEnable" = "فعالسازی ربات تلگرام"
"telegramBotEnableDesc" = "از طریق بات تلگرام به امکانات ابن پنل متصل شوید"
"pageSizeDesc" = "اندازه صفحه برای جدول ورودی‌ها. 0 = غیرفعال"
"remarkModel" = "نامکانفیگ و جداکننده"
"sampleRemark" = "نمونهنام"
"oldUsername" = "نامکاربری فعلی"
"currentPassword" = "رمزعبور فعلی"
"newUsername" = "نامکاربری جدید"
"newPassword" = "رمزعبور جدید"
"telegramBotEnable" = "فعالسازی ربات تلگرام"
"telegramBotEnableDesc" = "ربات تلگرام را فعال می‌کند"
"telegramToken" = "توکن تلگرام"
"telegramTokenDesc" = "توکن را باید از مدیر بات های تلگرام دریافت کنید @botfather"
"telegramChatId" = "آی دی تلگرام مدیریت"
"telegramChatIdDesc" = "از @userinfobot یا دستور '/id' در ربات برای دریافت شناسه های چت خود استفاده کنید. با استفاده از کاما میتونید چند آی دی را از هم جدا کنید. "
"telegramNotifyTime" = "مدت زمان نوتیفیکیشن ربات تلگرام"
"telegramNotifyTimeDesc" = "از فرمت زمان بندی لینوکس استفاده کنید "
"tgNotifyBackup" = "پشتیبان گیری از پایگاه داده"
"tgNotifyBackupDesc" = "ارسال کپی فایل پایگاه داده به همراه گزارش دوره ای"
"telegramTokenDesc" = "دریافت کنید @botfather توکن را می‌توانید از"
"telegramChatId" = "آیدی چت مدیر"
"telegramChatIdDesc" = "استفاده‌کنید'/id'یا دستور @userinfobot آی‌دی(های) چت تلگرام مدیر، برای دریافت شناسههای چت خود از"
"telegramNotifyTime" = "زمان نوتیفیکیشن"
"telegramNotifyTimeDesc" = "زمان‌اطلاع‌رسانی ربات تلگرام برای گزارش های دوره‌ای. از فرمت زمانبندی لینوکس استفادهکنید"
"tgNotifyBackup" = "پشتیبانگیری از دیتابیس"
"tgNotifyBackupDesc" = "فایل پشتیبان‌دیتابیس را بههمراه گزارش ارسال می‌کند"
"tgNotifyLogin" = "اعلان ورود"
"tgNotifyLoginDesc" = "نام کاربری، آدرس ای پی، و زمان وقتی که فردی سعی می‌کند به پنل شما وارد شود نمایش میدهد"
"tgNotifyLoginDesc" = "نامکاربری، آدرس آی‌پی، و زمان ورود، فردی که سعی می‌کند وارد پنل شود را نمایش میدهد"
"sessionMaxAge" = "بیشینه زمان جلسه وب"
"sessionMaxAgeDesc" = "بیشینه زمانی که میتوانید لاگین بمانید (واحد: دقیقه)"
"sessionMaxAgeDesc" = "بیشینه زمانی که میتوانید لاگین بمانید. واحد: دقیقه"
"expireTimeDiff" = "آستانه زمان باقی مانده"
"expireTimeDiffDesc" = "فاصله زمانی هشدار تا رسیدن به زمان انقضا (واحد: روز)"
"expireTimeDiffDesc" = "فاصله زمانی هشدار تا رسیدن به زمان انقضا. واحد: روز"
"trafficDiff" = "آستانه ترافیک باقی مانده"
"trafficDiffDesc" = "فاصله زمانی هشدار تا رسیدن به اتمام ترافیک (واحد: گیگابایت)"
"tgNotifyCpu" = "آستانه هشدار درصد پردازنده"
"tgNotifyCpuDesc" = "این ربات تلگرام در صورت استفاده پردازنده بیشتر از این درصد برای شما پیام ارسال می کند.(واحد: درصد)"
"timeZone" = "منظقه زمانی"
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقه زمانی اجرا می شوند. پنل را مجدداً راه اندازی می کند تا اعمال شود"
"trafficDiffDesc" = "فاصله زمانی هشدار تا رسیدن به اتمام ترافیک. واحد: گیگابایت"
"tgNotifyCpu" = "آستانه هشدار بار پردازنده"
"tgNotifyCpuDesc" = "اگر بار روی پردازنده ازاین آستانه فراتر رفت، برای شما پیام ارسال می‌شود. واحد: درصد"
"timeZone" = "منطقه زمانی"
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقهزمانی اجرا میشود"
"subSettings" = "سابسکریپشن"
"subEnable" = "فعال کردن سرویس"
"subEnableDesc" = "ویژگی سابسکریپشن با پیکربندی جداگانه"
"subListen" = "محدودیت آی‌پی"
"subListenDesc" = "برای استفاده از همه آی‌پی ها به طور پیش فرض خالی بگذارید"
"subPort" = "پورت سرویس"
"subPortDesc" = "شماره پورت برای ارائه خدمات سابسکریپشن"
"subCertPath" = "مسیر فایل کلید عمومی گواهی سابسکریپشن"
"subCertPathDesc" = "یک مسیر مطلق که با '/' شروع می شود را پر کنید."
"subKeyPath" = "مسیر فایل کلید خصوصی گواهی سابسکریپشن"
"subKeyPathDesc" = "یک مسیر مطلق که با '/' شروع می شود را پر کنید."
"subPath" = "مسیر ریشه سابسکریپشن"
"subPathDesc" = "باید با '/' شروع شود و با '/' ختم شود."
"subDomain" = "دامنه مخصوص سابسکریپشن"
"subDomainDesc" = "برای نظارت بر همه دامنه ها و آی‌پی ها به طور پیش فرض خالی بگذارید"
"subUpdates" = "فاصله به روز رسانی های سابسکریپشن"
"subUpdatesDesc" = "ساعت های فاصله بین به روز رسانی در برنامه کاربر"
"subEncrypt" = "رمزگذاری کانفیگ ها"
"subEncryptDesc" = "رمزگذاری کانفیگ های بازگشتی سابسکریپشن"
"subEnable" = "فعال‌سازی سرویس سابسکریپشن"
"subEnableDesc" = " سرویس سابسکریپشن را فعال‌می‌کند"
"subListen" = "آدرس آی‌پی"
"subListenDesc" = "آدرس آی‌پی برای سرویس سابسکریپشن. برای گوش دادن به‌تمام آی‌پیها خالیبگذارید"
"subPort" = "پورت"
"subPortDesc" = "شماره پورت برای سرویس سابسکریپشن. باید پورت استفاده نشده‌باشد"
"subCertPath" = "مسیر کلید عمومی"
"subCertPathDesc" = "مسیر فایل کلیدعمومی برای سرویس سابیکریپشن. با '/' شروعمیشود"
"subKeyPath" = "مسیر کلید خصوصی"
"subKeyPathDesc" = "مسیر فایل کلیدخصوصی برای سرویس سابسکریپشن. با '/' شروعمیشود"
"subPath" = "URI مسیر"
"subPathDesc" = رای سرویس سابسکریپشن. با '/' شروع و با '/' خاتمه می‌یابد URI مسیر"
"subDomain" = "نام دامنه"
"subDomainDesc" = "آدرس دامنه برای سرویس سابسکریپشن. برای گوش دادن به تمام دامنهها و آی‌پیها خالیبگذارید"
"subUpdates" = "فاصله بروزرسانی سابسکریپشن"
"subUpdatesDesc" = "فاصله مابین بروزرسانی در برنامه‌های کاربری - واحد: ساعت"
"subEncrypt" = "کدگذاری"
"subEncryptDesc" = "کدگذاری خواهدشد Base64 محتوای برگشتی سرویس سابسکریپشن برپایه"
"subShowInfo" = "نمایش اطلاعات مصرف"
"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در هر کانفیگ نمایش میدهد"
"subURI" = "آدرس پایه پروکسی معکوس"
"subURIDesc" = "آدرس پایه سابسکریپشن را برای استفاده در پشت پراکسی ها تغییر میدهد"
"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در برنامه‌های کاربری نمایش میدهد"
"subURI" = "پروکسی معکوس URI مسیر"
"subURIDesc" = "سابسکریپشن را برای استفاده در پشت پراکسیها تغییر میدهد URI مسیر"
[pages.settings.toasts]
"modifySettings" = "ویرایش تنظیمات"
"getSettings" = "دریافت تنظیمات"
"modifyUser" = "ویرایش کاربر"
"originalUserPassIncorrect" = "نام کاربری و رمز عبور فعلی اشتباه می باشد "
"userPassMustBeNotEmpty" = "نام کاربری و رمز عبور جدید نمیتواند خالی باشد "
"modifyUser" = "ویرایش مدیر"
"originalUserPassIncorrect" = "نامکاربری یا رمزعبور فعلی اشتباه‌است"
"userPassMustBeNotEmpty" = "نامکاربری یا رمزعبور جدید خالی‌است"
[pages.xray]
"title" = "تنظیمات Xray"
"save" = "ذخیره تنظیمات"
"title" = "پیکربندی ایکس‌ری"
"save" = "ذخیره"
"restart" = "ریستارت ایکس‌ری"
"basicTemplate" = "بخش الگو پایه"
"advancedTemplate" = "بخش الگو پیشرفته"
"generalConfigs" = "تنظیمات عمومی"
"generalConfigsDesc" = "این تنظیمات میتواند ترافیک کلی سرویس را متاثر کند"
"blockConfigs" = "مسدود سازی"
"blockConfigsDesc" = "این گزینه ها از اتصال کاربران به پروتکل ها و وب سایت های خاص جلوگیری می کند"
"blockCountryConfigs" = "تنظیمات برای مسدودسازی کشورها"
"blockCountryConfigsDesc" = "این گزینه اتصال کاربران به دامنه های کشوری خاص را مسدود می کند"
"directCountryConfigs" = "تنظیمات برای اتصال مستقیم کشورها"
"directCountryConfigsDesc" = "این گزینه کاربران را به دامنه های کشوری خاص را به طور مستقیم، متصل می کند"
"ipv4Configs" = "تنظیمات برای IPv4"
"ipv4ConfigsDesc" = "این گزینه فقط از طریق آیپی ورژن ۴ به دامنه های هدف هدایت می شود"
"Template" = "تنظیمات الگو ایکس ری"
"TemplateDesc" = "فایل پیکربندی ایکس ری نهایی بر اساس این الگو ایجاد میشود. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید!"
"FreedomStrategy" = "روش استفاده از شبکه خروجی مستقیم"
"FreedomStrategyDesc" = "تعیین روش استفاده از خروجی برای پرتکل مستقیم"
"RoutingStrategy" = "پیکربندی استراتژی حل دامنه در مسیریابی"
"RoutingStrategyDesc" = "تعیین استراتژی مسیریابی کلی برای پیدا کردن دامنه"
"Torrent" = "فیلتر کردن بیت تورنت"
"TorrentDesc" = "الگوی تنظیمات را برای فیلتر کردن پروتکل بیت تورنت برای کاربران تغییر میدهد"
"PrivateIp" = "جلوگیری از اتصال آیپی های خصوصی یا محلی"
"PrivateIpDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال آیپی های خصوصی یا محلی و بسته های سرگردان تغییر میدهد"
"Ads" = "مسدود کردن تبلیغات"
"AdsDesc" = "الگوی تنظیمات را برای مسدود کردن تبلیغات تغییر میدهد"
"Family" = "فعال کردن حالت خانواده"
"FamilyDesc" = "برای جلوگیری از ارتباط با وبسایت های ناامن"
"IRIp" = "جلوگیری از اتصال آیپی های ایران"
"IRIpDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال آیپی های ایران تغییر میدهد"
"IRDomain" = "جلوگیری از اتصال دامنه های ایران"
"IRDomainDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال دامنه های ایران تغییر میدهد"
"ChinaIp" = "جلوگیری از اتصال آیپی های چین"
"ChinaIpDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال آیپی های چین تغییر میدهد"
"ChinaDomain" = "جلوگیری از اتصال دامنه های چین"
"ChinaDomainDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال دامنه های چین تغییر میدهد"
"RussiaIp" = "جلوگیری از اتصال آیپی های روسیه"
"RussiaIpDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال آیپی های روسیه تغییر میدهد"
"RussiaDomain" = "جلوگیری از اتصال دامنه های روسیه"
"RussiaDomainDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال دامنه های روسیه تغییر میدهد"
"DirectIRIp" = "ارتباط مستقیم به آیپی های ایران"
"DirectIRIpDesc" = "الگوی تنظیمات را برای ارتباط مستقیم به آیپی های ایران تغییر میدهد"
"DirectIRDomain" = "ارتباط مستقیم به دامنه های ایران"
"DirectIRDomainDesc" = "الگوی تنظیمات را برای ارتباط مستقیم به دامنه های ایران تغییر میدهد"
"DirectChinaIp" = "ارتباط مستقیم به آیپی های چین"
"DirectChinaIpDesc" = "الگوی تنظیمات را برای ارتباط مستقیم به آیپی های چین تغییر میدهد"
"DirectChinaDomain" = "ارتباط مستقیم به دامنه های چین"
"DirectChinaDomainDesc" = "الگوی تنظیمات را برای ارتباط مستقیم به دامنه های چین تغییر میدهد"
"DirectRussiaIp" = "ارتباط مستقیم به آیپی های روسیه"
"DirectRussiaIpDesc" = "الگوی تنظیمات را برای ارتباط مستقیم به آیپی های روسیه تغییر میدهد"
"DirectRussiaDomain" = "ارتباط مستقیم به دامنه های روسیه"
"DirectRussiaDomainDesc" = "الگوی تنظیمات را برای ارتباط مستقیم به دامنه های روسیه تغییر میدهد"
"GoogleIPv4" = "استفاده از آیپی ورژن 4 برای اتصال به گوگل"
"GoogleIPv4Desc" = "مسیردهی جدید برای اتصال به گوگل با آیپی ورژن 4 اضافه میکند"
"NetflixIPv4" = "استفاده از آیپی ورژن 4 برای اتصال به نتفلیکس"
"NetflixIPv4Desc" = "مسیردهی جدید برای اتصال به نتفلیکس با آیپی ورژن 4 اضافه میکند"
"basicTemplate" = "پایه"
"advancedTemplate" = "پیشرفته"
"generalConfigs" = "استراتژی‌ کلی"
"generalConfigsDesc" = "این گزینه‌ها استراتژی کلی ترافیک را تعیین می‌کنند"
"blockConfigs" = "سپر محافظ"
"blockConfigsDesc" = "این گزینهها ترافیک را بر اساس پروتکلهای درخواستی خاص، و وب سایتها مسدود میکند"
"blockCountryConfigs" = "مسدودسازی کشور"
"blockCountryConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستی خاص مسدود میکند"
"directCountryConfigs" = "اتصال مستقیم کشور"
"directCountryConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستی خاص بصورت مستقیم ارسال میکند"
"ipv4Configs" = "IPv4 مسیریابی"
"ipv4ConfigsDesc" = "این گزینهها درخواست‌ها را فقط از طریق آیپینسخه4 به مقصد هدایت می‌کند"
"warpConfigs" = "تنظیمات برای وارپ"
"warpConfigsDesc" = ".وارپ ترافیک را از طریق سرورهای کلادفلر به وب سایت ها هدایت می کند"
"Template" = "‌پیکربندی پیشرفته الگو ایکس‌ری"
"TemplateDesc" = "فایل پیکربندی نهایی ایکس‌ری بر اساس این الگو ایجاد می‌شود"
"FreedomStrategy" = "Freedom استراتژی پروتکل"
"FreedomStrategyDesc" = "تعیین می‌کند Freedom استراتژی خروجی شبکه را برای پروتکل"
"RoutingStrategy" = "استراتژی کلی مسیریابی"
"RoutingStrategyDesc" = "استراتژی کلی مسیریابی برای حل تمام درخواست‌ها را تعیین می‌کند"
"Torrent" = "مسدودسازی پروتکل بیت‌تورنت"
"TorrentDesc" = "پروتکل بیت تورنت را مسدود می‌کند"
"PrivateIp" = "مسدودسازی اتصال آی‌پی‌های خصوصی"
"PrivateIpDesc" = "اتصال به آی‌پی‌های رنج خصوصی را مسدود می‌کند"
"Ads" = "مسدودسازی تبلیغات"
"AdsDesc" = "وب‌سایت‌های تبلیغاتی را مسدود می‌کند"
"Family" = "محافظت خانواده"
"FamilyDesc" = "محتوای مخصوص بزرگسالان، و وبسایت‌های ناامن را مسدود می‌کند"
"IRIp" = "مسدودسازی اتصال به آی‌پی‌های ایران"
"IRIpDesc" = "اتصال به آی‌پی‌های کشور ایران را مسدود می‌کند"
"IRDomain" = "مسدودسازی اتصال به دامنه‌های‌ ایران"
"IRDomainDesc" = "اتصال به دامنه‌های کشور ایران را مسدود می‌کند"
"ChinaIp" = "مسدودسازی اتصال به آی‌‌پی‌های چین"
"ChinaIpDesc" = "اتصال به آی‌پی‌های کشور چین را مسدود می‌کند"
"ChinaDomain" = "مسدودسازی اتصال به دامنه‌های چین"
"ChinaDomainDesc" = "اتصال به دامنه‌های کشور چین را مسدود می‌کند"
"RussiaIp" = "مسدودسازی اتصال به آی‌پی‌های روسیه"
"RussiaIpDesc" = "اتصال به آی‌پی‌های کشور روسیه را مسدود می‌کند"
"RussiaDomain" = "مسدودسازی اتصال به دامنه‌های روسیه"
"RussiaDomainDesc" = "اتصال به دامنه‌های کشور روسیه را مسدود می‌کند"
"DirectIRIp" = "اتصال مستقیم آی‌پی‌های ایران"
"DirectIRIpDesc" = "اتصال مستقیم به آی‌پی‌های کشور ایران"
"DirectIRDomain" = "اتصال مستقیم دامنه‌های ایران"
"DirectIRDomainDesc" = "اتصال مستقیم به دامنه‌های کشور ایران"
"DirectChinaIp" = "اتصال مستقیم آی‌پی‌های چین"
"DirectChinaIpDesc" = "اتصال مستقیم به آی‌پی‌های کشور چین"
"DirectChinaDomain" = "ارتباط مستقیم دامنه‌های چین"
"DirectChinaDomainDesc" = "اتصال مستقیم به دامنه‌های کشور چین"
"DirectRussiaIp" = "ارتباط مستقیم آی‌پی‌های روسیه"
"DirectRussiaIpDesc" = "اتصال مستقیم به آی‌پی‌های کشور روسیه"
"DirectRussiaDomain" = "ارتباط مستقیم دامنه های روسیه"
"DirectRussiaDomainDesc" = "اتصال مستقیم به دامنه‌های کشور روسیه"
"GoogleIPv4" = "گوگل"
"GoogleIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به گوگل هدایت میکند"
"NetflixIPv4" = "نتفلیکس"
"NetflixIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به نتفلیکس هدایت می‌کند"
"completeTemplate" = "کامل"
"GoogleWARP" = "گوگل"
"GoogleWARPDesc" = "ترافیک را از طریق وارپ به گوگل هدایت می‌کند"
"OpenAIWARP" = "چت جی‌پی‌تی"
"OpenAIWARPDesc" = "ترافیک را از طریق وارپ به چت جی‌پی‌تی هدایت می‌کند"
"NetflixWARP" = "نتفلیکس"
"NetflixWARPDesc" = "ترافیک را از طریق وارپ به نتفلیکس هدایت می‌کند"
"SpotifyWARP" = "اسپاتیفای"
"SpotifyWARPDesc" = " ترافیک را از طریق وارپ به اسپاتیفای هدایت می‌کند"
"Inbounds" = "ورودی‌ها"
"Outbounds" = "خروجی‌ها"
"Routings" = "قوانین مسیریابی"
"RoutingsDesc" = "اولویت هر قانون مهم است!"
"RoutingsDesc" = "اولویت هر قانون مهم است"
[pages.xray.rules]
"first" = "اولین"
@@ -371,7 +381,7 @@
"info" = "اطلاعات"
"add" = "افزودن قانون"
"edit" = "ویرایش قانون"
"useComma" = "موارد جدا شده با کاما"
"useComma" = "موارد جداشده با کاما"
[pages.xray.outbound]
"addOutbound" = "افزودن خروجی"
@@ -385,81 +395,89 @@
"domain" = "دامنه"
"type" = "نوع"
"bridge" = "پل"
"portal" = "پرتال"
"portal" = ورتال"
"intercon" = "اتصال میانی"
[pages.xray.wireguard]
"secretKey" = "کلید شخصی"
"publicKey" = "کلید عمومی"
"allowedIPs" = "آی‌پی‌های مجاز"
"endpoint" = "نقطه پایانی"
"psk" = "کلید مشترک"
"domainStrategy" = "استراتژی حل دامنه"
[tgbot]
"noResult" = "❗ نتیجه‌ای یافت نشد!"
"wentWrong" = "❌ مشکلی رخ داده است!"
"noInbounds" = " هیچ ورودی یافت نشد!"
"noResult" = "❗نتیجه‌ای یافت نشد"
"wentWrong" = "❌ مشکلی رخ دادهاست"
"noInbounds" = " هیچ ورودی یافت نشد"
"unlimited" = "♾ نامحدود"
"day" = "روز"
"days" = "روزها"
"unknown" = "نامشخص"
"inbounds" = "ورودی‌ها"
"clients" = لاینت‌ها"
"clients" = اربران"
[tgbot.commands]
"unknown" = "❗ دستور ناشناخته"
"pleaseChoose" = "👇 لطفاً انتخاب کنید:\r\n"
"help" = "🤖 به این ربات خوش آمدید! این ربات برای ارائه داده‌های خاص از سرور طراحی شده است و به شما امکان تغییرات لازم را می‌دهد.\r\n\r\n"
"pleaseChoose" = "👇 لطفاًانتخاب کنید:\r\n"
"help" = "🤖 به این ربات خوشآمدید! این ربات برای ارائه داده‌های خاص از وب پنل طراحی شدهاست و بهشما امکان تغییرات لازم را می‌دهد\r\n\r\n"
"start" = "👋 سلام <i>{{ .Firstname }}</i>.\r\n"
"welcome" = "🤖 به ربات مدیریت <b>{{ .Hostname }}</b> خوش آمدید.\r\n"
"status" = "✅ ربات در حالت عادی است!"
"usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!"
"getID" = "🆔 شناسه شما: <code>{{ .ID }}</code>"
"helpAdminCommands" = "برای جستجوی ایمیل مشتری:\r\n<code>/usage [ایمیل]</code>\r\n \r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n<code>/inbound [توضیح]</code>"
"helpClientCommands" = "برای جستجوی آمار، فقط از دستور زیر استفاده کنید:\r\n \r\n<code>/usage [UUID|رمز عبور]</code>\r\n \r\nاز UUID برای vmess/vless و از رمز عبور برای Trojan استفاده کنید."
"welcome" = "🤖 بهربات مدیریت <b>{{ .Hostname }}</b> خوشآمدید\r\n"
"status" = "✅ رباتدرحالتعادیاست"
"usage" = "❗ لطفا یک متن برای جستجو واردکنید"
"getID" = "🆔 شناسهشما: <code>{{ .ID }}</code>"
"helpAdminCommands" = "برای جستجوی ایمیل کاربر:\r\n<code>/usage [ایمیل]</code>\r\n \r\nبرای جستجوی ورودی‌ها (با آمار کاربر):\r\n<code>/inbound [توضیح]</code>"
"helpClientCommands" = "برای جستجوی آمار، فقط از دستور زیر استفادهکنید:\r\n \r\n<code>/usage [UUID|رمز عبور]</code>\r\n \r\nاز رمزعبور استفاده کنید Trojan/Shadowsocks و برای UUID از VMess/VLESS برای"
[tgbot.messages]
"cpuThreshold" = "🔴 میزان استفاده از CPU {{ .Percent }}% بیشتر از آستانه {{ .Threshold }}% است."
"loginSuccess" = "✅ با موفقیت به پنل وارد شدید.\r\n"
"loginFailed" = "❗️ ورود به پنل ناموفق بود.\r\n"
"report" = "🕰 گزارشات زمان‌بندی شده: {{ .RunTime }}\r\n"
"datetime" = "⏰ تاریخ-زمان: {{ .DateTime }}\r\n"
"hostname" = "💻 نام میزبان: {{ .Hostname }}\r\n"
"version" = "🚀 نسخه X-UI: {{ .Version }}\r\n"
"cpuThreshold" = "🔴 بار ‌پردازنده {{ .Percent }}% بیشتر از آستانه است {{ .Threshold }}%"
"loginSuccess" = "✅ باموفقیت به پنل واردشدید \r\n"
"loginFailed" = "❗️ ورود به پنل ناموفقبود \r\n"
"report" = "🕰 گزارشاتزمان‌بندیشده: {{ .RunTime }}\r\n"
"datetime" = "⏰ تاریخ‌وزمان: {{ .DateTime }}\r\n"
"hostname" = "💻 ناممیزبان: {{ .Hostname }}\r\n"
"version" = "🚀 نسخه‌پنل: {{ .Version }}\r\n"
"ipv6" = "🌐 IPv6: {{ .IPv6 }}\r\n"
"ipv4" = "🌐 IPv4: {{ .IPv4 }}\r\n"
"ip" = "🌐 آدرس IP: {{ .IP }}\r\n"
"serverUpTime" = "⏳ زمان کارکرد سرور: {{ .UpTime }} {{ .Unit }}\r\n"
"serverLoad" = "📈 بار سرور: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
"serverMemory" = "📋 حافظه سرور: {{ .Current }}/{{ .Total }}\r\n"
"tcpCount" = "🔹 تعداد ترافیک TCP: {{ .Count }}\r\n"
"udpCount" = "🔸 تعداد ترافیک UDP: {{ .Count }}\r\n"
"ip" = "🌐 آدرس‌آی‌پی: {{ .IP }}\r\n"
"serverUpTime" = "⏳ مدت‌کارکردسیستم: {{ .UpTime }} {{ .Unit }}\r\n"
"serverLoad" = "📈 بارسیستم: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n"
"serverMemory" = "📋 RAM: {{ .Current }}/{{ .Total }}\r\n"
"tcpCount" = "🔹 TCP: {{ .Count }}\r\n"
"udpCount" = "🔸 UDP: {{ .Count }}\r\n"
"traffic" = "🚦 ترافیک: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
"xrayStatus" = " وضعیت Xray: {{ .State }}\r\n"
"username" = "👤 نام کاربری: {{ .Username }}\r\n"
"xrayStatus" = " وضعیت‌ایکس‌ری: {{ .State }}\r\n"
"username" = "👤 نامکاربری: {{ .Username }}\r\n"
"time" = "⏰ زمان: {{ .Time }}\r\n"
"inbound" = "📍 ورودی: {{ .Remark }}\r\n"
"inbound" = "📍 نام‌ورودی: {{ .Remark }}\r\n"
"port" = "🔌 پورت: {{ .Port }}\r\n"
"expire" = "📅 تاریخ انقضا: {{ .DateTime }}\r\n \r\n"
"expireIn" = "📅 باقیمانده از انقضا: {{ .Time }}\r\n \r\n"
"expire" = "📅 تاریخانقضا: {{ .DateTime }}\r\n \r\n"
"expireIn" = "📅 باقیمانده‌تاانقضا: {{ .Time }}\r\n \r\n"
"active" = "💡 فعال: {{ .Enable }}\r\n"
"online" = "🌐 وضعیت اتصال: {{ .Status }}\r\n"
"email" = "📧 ایمیل: {{ .Email }}\r\n"
"upload" = "🔼 آپلود↑: {{ .Upload }}\r\n"
"download" = "🔽 دانلود↓: {{ .Download }}\r\n"
"total" = "🔄 کل: {{ .UpDown }} / {{ .Total }}\r\n"
"exhaustedMsg" = "🚨 {{ .Type }} به اتمام رسیده است:\r\n"
"exhaustedCount" = "🚨 تعداد {{ .Type }} به اتمام رسیده:\r\n"
"onlinesCount" = "🌐 تعداد کاربران آنلاین: {{ .Count }}\r\n"
"exhaustedMsg" = "🚨 {{ .Type }} بهاتمامرسیدهاست:\r\n"
"exhaustedCount" = "🚨 تعداد {{ .Type }} بهاتمامرسیده‌است:\r\n"
"onlinesCount" = "🌐 کاربرانآنلاین: {{ .Count }}\r\n"
"disabled" = "🛑 غیرفعال: {{ .Disabled }}\r\n"
"depleteSoon" = "🔜 به زودی به پایان خواهد رسید: {{ .Deplete }}\r\n \r\n"
"backupTime" = "🗄 زمان پشتیبان‌گیری: {{ .Time }}\r\n"
"depleteSoon" = "🔜 بهزودیبهپایانخواهدرسید: {{ .Deplete }}\r\n \r\n"
"backupTime" = "🗄 زمانپشتیبان‌گیری: {{ .Time }}\r\n"
"yes" = "✅ بله"
"no" = "❌ خیر"
[tgbot.buttons]
"dbBackup" = "دریافت پشتیبان پایگاه داده"
"serverUsage" = "استفاده از سرور"
"dbBackup" = "دریافت پشتیبان دیتابیس"
"serverUsage" = "استفاده از سیستم"
"getInbounds" = "دریافت ورودی‌ها"
"depleteSoon" = "به زودی به پایان خواهد رسید"
"depleteSoon" = "بهزودی به پایان خواهد رسید"
"clientUsage" = "دریافت آمار کاربر"
"onlines" = "کاربران آنلاین"
"commands" = "دستورات"
[tgbot.answers]
"getInboundsFailed" = "❌ دریافت ورودی‌ها با خطا مواجه شد."
"askToAddUser" = "پیکربندی شما یافت نشد!\r\nشما باید نام کاربری تلگرام خود را پیکربندی کنید و از مدیر خود درخواست اضافه کردن آن به پیکربندی خود بکنید."
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود درخواست استفاده از نام کاربری تلگرام خود در پیکربندی (ها) خود را بکنید.\r\n\r\nنام کاربری شما: <b>@{{ .TgUserName }}</b>"
"getInboundsFailed" = "❌ دریافت ورودی‌ها باخطا مواجه شد"
"askToAddUser" = "پیکربندی شما پیدا نشد!\r\nشما باید نامکاربری تلگرام خود را پیکربندی کنید و از مدیر پنل خود بخواهید که آن را به پیکربندی شما اضافه کند"
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر پنل درخواست کنید اطلاعات تلگرام شما را در پیکربندی(های) مربوط به‌شما تنظیم‌کند \r\n\r\nنامکاربری شما: @{{ .TgUserName }}"

View File

@@ -32,7 +32,7 @@
"transmission" = "Протокол передачи"
"host" = "Хост"
"path" = "Путь"
"camouflage" = "Маскировка"
"camouflage" = "Затемнение"
"status" = "Статус"
"enabled" = "Включено"
"disabled" = "Отключено"
@@ -60,10 +60,10 @@
"settings" = "Настройки"
"xray" = "Xray Настройки"
"logout" = "Выйти"
"link" = "Другое"
"link" = "Менеджмент"
[pages.login]
"title" = "Войти"
"title" = "Добро пожаловать"
"loginAgain" = "Время сессии истекло. Пожалуйста, войдите в систему снова"
[pages.login.toasts]
@@ -167,7 +167,7 @@
"emailDesc" = "Пожалуйста, укажите уникальный Email"
"setDefaultCert" = "Установить сертификат с панели"
"telegramDesc" = "Используйте идентификатор Telegram без символа @ или идентификатора чата (можно получить его здесь @userinfobot или использовать команду '/id' в боте)"
"subscriptionDesc" = "вы можете найти свою ссылку подписки в разделе «Подробнее», также вы можете использовать одно и то же имя для нескольких конфигов"
"subscriptionDesc" = "вы можете найти свою ссылку подписки в разделе «Подробнее», также вы можете использовать одно и то же имя для нескольких клиенты"
"info" = "Информация"
"same" = "Тот же"
"inboundData" = "Входящие данные"
@@ -188,10 +188,10 @@
"prefix" = "Префикс"
"postfix" = "Постфикс"
"delayedStart" = "Начать со времени первого подключения"
"expireDays" = "Срок действия"
"expireDays" = "Длительность"
"days" = "дней"
"renew" = "Автопродление"
"renewDesc" = "Автоматическое продление через несколько дней после истечения срока действия. 0 = отключить"
"renewDesc" = "Автопродление после истечения срока действия. (0 = отключить)(единица: день) "
[pages.inbounds.toasts]
"obtain" = "Получить"
@@ -312,6 +312,8 @@
"directCountryConfigsDesc" = "Эти параметры будут подключать пользователей напрямую к доменам определенной страны."
"ipv4Configs" = "Настройки IPv4"
"ipv4ConfigsDesc" = "Эти параметры будут маршрутизироваться к целевым доменам только через IPv4"
"warpConfigs" = "Настройки WARP"
"warpConfigsDesc" = "WARP будет направлять трафик на веб-сайты через серверы Cloudflare"
"Template" = "Шаблон конфигурации Xray"
"TemplateDesc" = "Создание файла конфигурации Xray на основе этого шаблона."
"FreedomStrategy" = "Настроить стратегию протокола Freedom"
@@ -354,6 +356,14 @@
"GoogleIPv4Desc" = "Применить маршрутизацию Google для подключения к IPv4."
"NetflixIPv4" = "Использовать IPv4 для Netflix"
"NetflixIPv4Desc" = "Применить маршрутизацию Netflix для подключения к IPv4."
"GoogleWARP" = "Маршрутизация Google через WARP"
"GoogleWARPDesc" = "Добавить маршрутизацию для Google через WARP"
"OpenAIWARP" = "Маршрутизация OpenAI (ChatGPT) через WARP"
"OpenAIWARPDesc" = "Добавить маршрутизацию для OpenAI (ChatGPT) через WARP"
"NetflixWARP" = "Маршрутизация Netflix через WARP"
"NetflixWARPDesc" = "Добавить маршрутизацию для Netflix через WARP"
"SpotifyWARP" = "Маршрутизация Spotify через WARP"
"SpotifyWARPDesc" = "Добавить маршрутизацию для Spotify через WARP"
"completeTemplate" = "Все"
"Inbounds" = "Входящие"
"Outbounds" = "Исходящие"
@@ -368,7 +378,7 @@
"source" = "Источник"
"dest" = "Пункт назначения"
"inbound" = "Входящий"
"outboun" = "Исходящий"
"outbound" = "Исходящий"
"info" = "Информация"
"add" = "Добавить правило"
"edit" = "Редактировать правило"
@@ -389,6 +399,14 @@
"portal" = "Портал"
"intercon" = "Соединение"
[pages.xray.wireguard]
"secretKey" = "Секретный ключ"
"publicKey" = "Открытый ключ"
"allowedIPs" = "Разрешенные IP-адреса"
"endpoint" = "Конечная точка"
"psk" = "Общий ключ"
"domainStrategy" = "Стратегия домена"
[tgbot]
"noResult" = "❗ Нет результатов!"
"wentWrong" = "❌ Что-то пошло не так!"

View File

@@ -32,7 +32,7 @@
"transmission" = "Truyền tải"
"host" = "Máy chủ"
"path" = "Đường dẫn"
"camouflage" = "Ngụy trang"
"camouflage" = "Sự làm xáo trộn"
"status" = "Trạng thái"
"enabled" = "Đã kích hoạt"
"disabled" = "Đã tắt"
@@ -60,10 +60,10 @@
"settings" = "Cài đặt bảng điều khiển"
"xray" = "Cài đặt Xray"
"logout" = "Đăng xuất"
"link" = "Khác"
"link" = "Sự quản lý"
[pages.login]
"title" = "Đăng nhập"
"title" = "Chào mừng"
"loginAgain" = "Thời hạn đăng nhập đã hết, Vui lòng đăng nhập lại."
[pages.login.toasts]
@@ -100,8 +100,8 @@
"backup" = "Phục hồi dữ liệu đã lưu"
"backupTitle" = "Sao lưu và Khôi phục cơ sở dữ liệu"
"backupDescription" = "Bạn hãy nhớ sao lưu trước khi nhập cơ sở dữ liệu mới."
"exportDatabase" = "Tải xuống cơ sở dữ liệu"
"importDatabase" = "Tải lên cơ sở dữ liệu"
"exportDatabase" = "Sao lưu"
"importDatabase" = "Khôi phục"
[pages.inbounds]
"title" = "Điểm vào (Inbounds)"
@@ -167,7 +167,7 @@
"emailDesc" = "vui lòng cung cấp một địa chỉ email duy nhất."
"setDefaultCert" = "Đặt chứng chỉ từ bảng điều khiển"
"telegramDesc" = "Sử dụng ID Telegram không có @ hoặc ID trò chuyện (bạn có thể lấy nó tại đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)"
"subscriptionDesc" = "Bạn có thể tìm thấy liên kết phụ của mình trên Chi tiết, bạn cũng có thể sử dụng cùng tên cho một số cấu hình"
"subscriptionDesc" = "Bạn có thể tìm thấy liên kết phụ của mình trên Chi tiết, bạn cũng có thể sử dụng cùng tên cho một số khách hàng"
"info" = "Thông tin"
"same" = "Như nhau"
"inboundData" = "Dữ liệu gửi đến"
@@ -188,10 +188,10 @@
"prefix" = "Tiền Tố (Được ưu đãi)"
"postfix" = "Hậu tố"
"delayedStart" = "Bắt đầu sau lần sử dụng đầu tiên"
"expireDays" = "Số ngày hết hạn"
"expireDays" = "Khoảng thời gian"
"days" = "Ngày(s)"
"renew" = "Tự động gia hạn"
"renewDesc" = "Tự động gia hạn ngày sau khi hết hạn. 0 = tắt"
"renewDesc" = "Tự động gia hạn sau khi hết hạn. (0 = tắt)(đơn vị: ngày)"
[pages.inbounds.toasts]
"obtain" = "Nhận được"
@@ -312,6 +312,8 @@
"directCountryConfigsDesc" = "Những tùy chọn này sẽ kết nối người dùng trực tiếp đến các tên miền quốc gia cụ thể."
"ipv4Configs" = "Cấu hình IPv4"
"ipv4ConfigsDesc" = "Những tùy chọn này sẽ chỉ định kết nối đến các tên miền mục tiêu qua IPv4."
"warpConfigs" = "Cấu hình WARP"
"warpConfigsDesc" = "WARP sẽ định tuyến lưu lượng đến các trang web qua máy chủ Cloudflare."
"Template" = "Mẫu cấu hình Xray"
"TemplateDesc" = "Tạo tệp cấu hình Xray cuối cùng dựa trên mẫu này."
"FreedomStrategy" = "Cấu hình chiến lược cho giao thức tự do"
@@ -354,6 +356,14 @@
"GoogleIPv4Desc" = "Thêm định tuyến để Google kết nối với IPv4."
"NetflixIPv4" = "Sử dụng IPv4 cho Netflix"
"NetflixIPv4Desc" = "Thêm định tuyến cho Netflix để kết nối với IPv4."
"GoogleWARP" = "Định tuyến Google qua WARP."
"GoogleWARPDesc" = "Thêm định tuyến cho Google qua WARP."
"OpenAIWARP" = "Định tuyến OpenAI (ChatGPT) qua WARP."
"OpenAIWARPDesc" = "Thêm định tuyến cho OpenAI (ChatGPT) qua WARP."
"NetflixWARP" = "Định tuyến Netflix qua WARP."
"NetflixWARPDesc" = "Thêm định tuyến cho Netflix qua WARP."
"SpotifyWARP" = "Định tuyến Spotify qua WARP."
"SpotifyWARPDesc" = "Thêm định tuyến cho Spotify qua WARP."
"completeTemplate" = "Tất cả"
"Inbounds" = "Đầu vào"
"Outbounds" = "Đầu ra"
@@ -389,6 +399,14 @@
"portal" = "Cổng thông tin"
"intercon" = "Kết nối"
[pages.xray.wireguard]
"secretKey" = "Chìa khoá bí mật"
"publicKey" = "Khóa công khai"
"allowedIPs" = "IP được phép"
"endpoint" = "Điểm cuối"
"psk" = "Khóa chia sẻ"
"domainStrategy" = "Chiến lược tên miền"
[tgbot]
"noResult" = "❗ Không có kết quả!"
"wentWrong" = "❌ Đã xảy ra lỗi!"

View File

@@ -32,7 +32,7 @@
"transmission" = "传输"
"host" = "主持人"
"path" = "小路"
"camouflage" = "伪装"
"camouflage" = "混淆"
"status" = "状态"
"enabled" = "开启"
"disabled" = "关闭"
@@ -60,10 +60,10 @@
"settings" = "面板设置"
"xray" = "Xray 设置"
"logout" = "退出登录"
"link" = "其他"
"link" = "管理"
[pages.login]
"title" = "登录"
"title" = "欢迎"
"loginAgain" = "登录时效已过,请重新登录"
[pages.login.toasts]
@@ -100,8 +100,8 @@
"backup" = "备份"
"backupTitle" = "备份数据库"
"backupDescription" = "请记住在导入新数据库之前进行备份"
"exportDatabase" = "下载数据库"
"importDatabase" = "上传数据库"
"exportDatabase" = "备份"
"importDatabase" = "恢复"
[pages.inbounds]
"title" = "入站列表"
@@ -167,7 +167,7 @@
"emailDesc" = "电子邮件必须完全唯"
"setDefaultCert" = "从面板设置证书"
"telegramDesc" = "使用 Telegram ID不包含 @ 符号或聊天 ID可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)"
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,可以多个配置使用相同的名称"
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,可以多个客户端使用相同的名称"
"info" = "信息"
"same" = "相同"
"inboundData" = "入站数据"
@@ -188,10 +188,10 @@
"prefix" = "前缀"
"postfix" = "后缀"
"delayedStart" = "首次使用后开始"
"expireDays" = "过期天数"
"expireDays" = "期间"
"days" = "天"
"renew" = "自动续订"
"renewDesc" = "期后自动续订。0 = 禁用"
"renewDesc" = "期后自动续订。(0 = 禁用)(单元: 天)"
[pages.inbounds.toasts]
"obtain" = "获取"
@@ -312,6 +312,8 @@
"directCountryConfigsDesc" = "这些选项会将用户直接连接到特定国家/地区的域。"
"ipv4Configs" = "IPv4 配置"
"ipv4ConfigsDesc" = "此选项将仅通过 IPv4 路由到目标域"
"warpConfigs" = "WARP 配置"
"warpConfigsDesc" = "WARP 将通过 Cloudflare 服务器将流量路由到网站。"
"Template" = "Xray 配置模板"
"TemplateDesc" = "以该模型为基础生成最终的Xray配置文件重新启动面板生成效率"
"FreedomStrategy" = "配置自由协议的策略"
@@ -354,6 +356,14 @@
"GoogleIPv4Desc" = "添加谷歌连接IPv4的路由"
"NetflixIPv4" = "为 Netflix 使用 IPv4"
"NetflixIPv4Desc" = "添加Netflix连接IPv4的路由"
"GoogleWARP" = "将谷歌路由到 WARP"
"GoogleWARPDesc" = "为谷歌添加路由到WARP"
"OpenAIWARP" = "将 OpenAI (ChatGPT) 路由到 WARP"
"OpenAIWARPDesc" = "将OpenAIChatGPT路由添加到WARP"
"NetflixWARP" = "将 Netflix 路由到 WARP"
"NetflixWARPDesc" = "为Netflix添加路由到WARP"
"SpotifyWARP" = "将 Spotify 路由到 WARP"
"SpotifyWARPDesc" = "为Spotify添加路由到WARP"
"completeTemplate" = "全部"
"Inbounds" = "界内"
"Outbounds" = "出站"
@@ -361,7 +371,7 @@
"RoutingsDesc" = "每条规则的优先级都很重要"
[pages.xray.rules]
"firsto" = "第一个"
"first" = "第一个"
"last" = "最后"
"up" = "向上"
"down" = "向下"
@@ -382,13 +392,21 @@
"tag" = "标签"
"tagDesc" = "独特的标签"
"address" = "地址"
"rreverse" = "反转"
"reverse" = "反转"
"domain" = "域名"
"type" = "类型"
"bridge" = "桥"
"portal" = "门户"
"intercon" = "互连"
[pages.xray.wireguard]
"secretKey" = "密钥"
"publicKey" = "公钥"
"allowedIPs" = "允许的 IP"
"endpoint" = "终点"
"psk" = "共享密钥"
"domainStrategy" = "域策略"
[tgbot]
"noResult" = "❗ 没有结果!"
"wentWrong" = "❌ 出了点问题!"

101
x-ui.sh
View File

@@ -115,6 +115,24 @@ update() {
fi
}
custom_version() {
echo "Enter the panel version (like 1.6.0):"
read panel_version
if [ -z "$panel_version" ]; then
echo "Panel version cannot be empty. Exiting."
exit 1
fi
download_link="https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh"
# Use the entered panel version in the download link
install_command="bash <(curl -Ls $download_link) $panel_version"
echo "Downloading and installing panel version $panel_version..."
eval $install_command
}
uninstall() {
confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" "n"
if [[ $? != 0 ]]; then
@@ -283,12 +301,6 @@ show_log() {
fi
}
migrate_v2_ui() {
/usr/local/x-ui/x-ui v2-ui
before_show_menu
}
install_bbr() {
# temporary workaround for installing bbr
bash <(curl -L -s https://raw.githubusercontent.com/teddysun/across/master/bbr.sh)
@@ -362,7 +374,7 @@ show_status() {
check_status
case $? in
0)
echo -e "Panel state: ${green}Runing${plain}"
echo -e "Panel state: ${green}Running${plain}"
show_enable_status
;;
1)
@@ -397,7 +409,7 @@ check_xray_status() {
show_xray_status() {
check_xray_status
if [[ $? == 0 ]]; then
echo -e "xray state: ${green}Runing${plain}"
echo -e "xray state: ${green}Running${plain}"
else
echo -e "xray state: ${red}Not Running${plain}"
fi
@@ -676,30 +688,31 @@ show_menu() {
————————————————
${green}1.${plain} Install
${green}2.${plain} Update
${green}3.${plain} Uninstall
${green}3.${plain} Custom Version
${green}4.${plain} Uninstall
————————————————
${green}4.${plain} Reset Username and Password
${green}5.${plain} Reset Panel Settings
${green}6.${plain} Set Panel Port
${green}7.${plain} View Panel Settings
${green}5.${plain} Reset Username and Password
${green}6.${plain} Reset Panel Settings
${green}7.${plain} Set Panel Port
${green}8.${plain} View Panel Settings
————————————————
${green}8.${plain} Start
${green}9.${plain} Stop
${green}10.${plain} Restart
${green}11.${plain} Check State
${green}12.${plain} Check Logs
${green}9.${plain} Start
${green}10.${plain} Stop
${green}11.${plain} Restart
${green}12.${plain} Check State
${green}13.${plain} Check Logs
————————————————
${green}13.${plain} Enable Autostart
${green}14.${plain} Disable Autostart
${green}14.${plain} Enable Autostart
${green}15.${plain} Disable Autostart
————————————————
${green}15.${plain} A Key Installation BBR (latest kernel)
${green}16.${plain} SSL Certificate Management
${green}17.${plain} Cloudflare SSL Certificate
${green}18.${plain} Update Geo Files
${green}16.${plain} A Key Installation BBR (latest kernel)
${green}17.${plain} SSL Certificate Management
${green}18.${plain} Cloudflare SSL Certificate
${green}19.${plain} Update Geo Files
————————————————
"
show_status
echo && read -p "Please enter your selection [0-18]: " num
echo && read -p "Please enter your selection [0-19]: " num
case "${num}" in
0)
@@ -712,55 +725,58 @@ show_menu() {
check_install && update
;;
3)
check_install && uninstall
check_install && custom_version
;;
4)
check_install && reset_user
check_install && uninstall
;;
5)
check_install && reset_config
check_install && reset_user
;;
6)
check_install && set_port
check_install && reset_config
;;
7)
check_install && check_config
check_install && set_port
;;
8)
check_install && start
check_install && check_config
;;
9)
check_install && stop
check_install && start
;;
10)
check_install && restart
check_install && stop
;;
11)
check_install && status
check_install && restart
;;
12)
check_install && show_log
check_install && status
;;
13)
check_install && enable
check_install && show_log
;;
14)
check_install && disable
check_install && enable
;;
15)
install_bbr
check_install && disable
;;
16)
ssl_cert_issue_main
install_bbr
;;
17)
ssl_cert_issue_CF
ssl_cert_issue_main
;;
18)
ssl_cert_issue_CF
;;
19)
update_geo
;;
*)
LOGE "Please enter the correct number [0-18]"
LOGE "Please enter the correct number [0-19]"
;;
esac
}
@@ -788,9 +804,6 @@ if [[ $# > 0 ]]; then
"log")
check_install 0 && show_log 0
;;
"v2-ui")
check_install 0 && migrate_v2_ui 0
;;
"update")
check_install 0 && update 0
;;

View File

@@ -20,8 +20,13 @@ func (lw *LogWriter) Write(m []byte) (n int, err error) {
lw.lastLine = messages[len(messages)-1]
for _, msg := range messages {
messageBody := msg
// Remove timestamp
messageBody := strings.TrimSpace(strings.SplitN(msg, " ", 3)[2])
splittedMsg := strings.SplitN(msg, " ", 3)
if len(splittedMsg) > 2 {
messageBody = strings.TrimSpace(strings.SplitN(msg, " ", 3)[2])
}
// Find level in []
startIndex := strings.Index(messageBody, "[")