Compare commits
154 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0bbacf013 | ||
|
|
34af7f8bfa | ||
|
|
b569c21fec | ||
|
|
c4a5c059e3 | ||
|
|
c21ed90da0 | ||
|
|
9b58277945 | ||
|
|
5a4a42aeb8 | ||
|
|
9476472bf6 | ||
|
|
2ce9c3cc81 | ||
|
|
0a8bfc2725 | ||
|
|
c5bbb6b632 | ||
|
|
f497a8dbcc | ||
|
|
4290081486 | ||
|
|
ccda652e69 | ||
|
|
2982d809ab | ||
|
|
7ad4a3dffc | ||
|
|
c0ef53e542 | ||
|
|
b7d1c84cd0 | ||
|
|
111bfe5d2e | ||
|
|
6e59aa14b0 | ||
|
|
a4cf77422f | ||
|
|
35df2a0505 | ||
|
|
9f445686a4 | ||
|
|
0fc935e996 | ||
|
|
adb08a60cf | ||
|
|
e3576e8a85 | ||
|
|
9c065aed4e | ||
|
|
7abb092211 | ||
|
|
937bfb4c78 | ||
|
|
1bcdc54b68 | ||
|
|
eb58314c53 | ||
|
|
c158e6ec73 | ||
|
|
5ae587ee81 | ||
|
|
d40fa46851 | ||
|
|
19a31686da | ||
|
|
13f7e07128 | ||
|
|
0e3691fdbd | ||
|
|
e359b5c75e | ||
|
|
3b3bd3dea4 | ||
|
|
8f36b7ea84 | ||
|
|
569d99512c | ||
|
|
ac84553a68 | ||
|
|
610db7827d | ||
|
|
088b55c9ed | ||
|
|
c800e29900 | ||
|
|
14435db0d8 | ||
|
|
bd6402562e | ||
|
|
d16ad11136 | ||
|
|
6c27e4177d | ||
|
|
bebf83f06c | ||
|
|
07bf741b15 | ||
|
|
5e5851029d | ||
|
|
e6020850fc | ||
|
|
80183f61e8 | ||
|
|
1b9432ff37 | ||
|
|
f1f813269c | ||
|
|
a23f390402 | ||
|
|
2950ce0c17 | ||
|
|
514c4909a4 | ||
|
|
99cadf7652 | ||
|
|
4ca36d64a8 | ||
|
|
863009dcaa | ||
|
|
2ef5ccc2fd | ||
|
|
744583b4e7 | ||
|
|
b36032e22c | ||
|
|
ac7901abba | ||
|
|
dff2496d73 | ||
|
|
d97d36bb9e | ||
|
|
b0d2cb93e1 | ||
|
|
f98d78c356 | ||
|
|
d85226dc79 | ||
|
|
1c2b6095c9 | ||
|
|
5f8c8f4525 | ||
|
|
6a49e99a2c | ||
|
|
6062031de4 | ||
|
|
fb2b58110d | ||
|
|
c385662783 | ||
|
|
4a05188a7f | ||
|
|
1454c4ebc5 | ||
|
|
4b1c76e972 | ||
|
|
f1f5d323e8 | ||
|
|
e37f2d3222 | ||
|
|
4f2f855c04 | ||
|
|
dcab4e6f9c | ||
|
|
e703055793 | ||
|
|
7efe1d60d5 | ||
|
|
1d84284b6d | ||
|
|
8404b33232 | ||
|
|
41d39dfaa8 | ||
|
|
761eb5f384 | ||
|
|
e72f67ca54 | ||
|
|
b8df15171e | ||
|
|
5f531f2de1 | ||
|
|
8335238eb3 | ||
|
|
aaf68ecb21 | ||
|
|
db6781f311 | ||
|
|
a85b02c6ab | ||
|
|
19a832cad8 | ||
|
|
f0dd6152fd | ||
|
|
decac2ef74 | ||
|
|
c3ce1da0d6 | ||
|
|
02bc488c1c | ||
|
|
b22f859c38 | ||
|
|
98869c7169 | ||
|
|
150c89db72 | ||
|
|
fe0a8375a3 | ||
|
|
80cfbefd75 | ||
|
|
f2ee18235f | ||
|
|
f48df1e5c0 | ||
|
|
b24855082e | ||
|
|
27434f3235 | ||
|
|
cdb6eac0e6 | ||
|
|
9e13513205 | ||
|
|
b09f52357c | ||
|
|
ac08e86747 | ||
|
|
c9c8abe97b | ||
|
|
0b8beafc89 | ||
|
|
8b6e3491c4 | ||
|
|
6cf2b56f9b | ||
|
|
19b95829e0 | ||
|
|
4bea427c79 | ||
|
|
da7e4d51d6 | ||
|
|
43713fbdf8 | ||
|
|
dc29e858c9 | ||
|
|
c30c6f08f3 | ||
|
|
7c892ac051 | ||
|
|
75dd7b93f5 | ||
|
|
d5de8e1bf3 | ||
|
|
16b4795956 | ||
|
|
e5835c299c | ||
|
|
4fdef3cfde | ||
|
|
cf6a8bd463 | ||
|
|
59a84e844c | ||
|
|
6b0c9a5fad | ||
|
|
77edea5419 | ||
|
|
521870df0a | ||
|
|
dc1c1eb998 | ||
|
|
e78427245a | ||
|
|
fbcab5bc52 | ||
|
|
89c79c3ec3 | ||
|
|
566cd9e9c4 | ||
|
|
ad78cec7c7 | ||
|
|
176ab5f48e | ||
|
|
9c4fa23931 | ||
|
|
2938694c45 | ||
|
|
88d0fb9753 | ||
|
|
d23a7f81ef | ||
|
|
2e363445fc | ||
|
|
33d983bc20 | ||
|
|
3e7c7831bc | ||
|
|
374d49eb92 | ||
|
|
663cf5649f | ||
|
|
095ebccbb0 | ||
|
|
f4bb6b0517 |
70
.github/workflows/docker.yml
vendored
70
.github/workflows/docker.yml
vendored
@@ -1,41 +1,55 @@
|
||||
name: Release 3X-UI for Docker
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
build_and_push:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
hsanaeii/3x-ui
|
||||
ghcr.io/mhsanaei/3x-ui
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=pep440,pattern={{version}}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
platforms: linux/amd64, linux/arm64/v8, linux/arm/v7, linux/arm/v6, linux/386
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64, linux/arm64/v8, linux/arm/v7, linux/arm/v6, linux/386
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -1,10 +1,10 @@
|
||||
name: Release 3X-UI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
cd x-ui/bin
|
||||
|
||||
# Download dependencies
|
||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.9.7/"
|
||||
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v24.11.21/"
|
||||
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
||||
wget ${Xray_URL}Xray-linux-64.zip
|
||||
unzip Xray-linux-64.zip
|
||||
|
||||
@@ -27,7 +27,7 @@ case $1 in
|
||||
esac
|
||||
mkdir -p build/bin
|
||||
cd build/bin
|
||||
wget "https://github.com/XTLS/Xray-core/releases/download/v24.9.7/Xray-linux-${ARCH}.zip"
|
||||
wget "https://github.com/XTLS/Xray-core/releases/download/v24.11.21/Xray-linux-${ARCH}.zip"
|
||||
unzip "Xray-linux-${ARCH}.zip"
|
||||
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
||||
mv xray "xray-linux-${FNAME}"
|
||||
|
||||
@@ -30,38 +30,62 @@
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
## Instalar una Versión Personalizada
|
||||
## Instalar versión antigua (no recomendamos)
|
||||
|
||||
Para instalar la versión deseada, agrega la versión al final del comando de instalación. Por ejemplo, ver `v2.4.0`:
|
||||
Para instalar la versión deseada, utiliza el siguiente comando de instalación. Por ejemplo, ver `v1.7.9`:
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.0
|
||||
VERSION=v1.7.9 && <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## Certificado SSL
|
||||
|
||||
<details>
|
||||
<summary>Haz clic para el Certificado SSL</summary>
|
||||
<summary>Haga clic para ver los detalles del certificado SSL</summary>
|
||||
|
||||
### Cloudflare
|
||||
### ACME
|
||||
|
||||
El script de gestión tiene una aplicación de certificado SSL incorporada para Cloudflare. Para usar este script para colocar un certificado, necesitas lo siguiente:
|
||||
Para gestionar certificados SSL utilizando ACME:
|
||||
|
||||
- Correo electrónico registrado en Cloudflare
|
||||
- Clave Global de API de Cloudflare
|
||||
- El nombre de dominio se ha resuelto en el servidor actual a través de Cloudflare
|
||||
|
||||
**1:** Ejecuta el comando`x-ui`en la terminal, luego elige `Certificado SSL de Cloudflare`.
|
||||
1. Asegúrate de que tu dominio esté correctamente resuelto al servidor.
|
||||
2. Ejecuta el comando `x-ui` en la terminal y elige `Gestión de Certificados SSL`.
|
||||
3. Se te presentarán las siguientes opciones:
|
||||
|
||||
- **Get SSL:** Obtener certificados SSL.
|
||||
- **Revoke:** Revocar certificados SSL existentes.
|
||||
- **Force Renew:** Forzar la renovación de certificados SSL.
|
||||
- **Show Existing Domains:** Mostrar todos los certificados de dominio disponibles en el servidor.
|
||||
- **Set Certificate Paths for the Panel:** Especificar el certificado para tu dominio que será utilizado por el panel.
|
||||
|
||||
### Certbot
|
||||
```
|
||||
|
||||
Para instalar y usar Certbot:
|
||||
|
||||
```sh
|
||||
apt-get install certbot -y
|
||||
certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com
|
||||
certbot renew --dry-run
|
||||
```
|
||||
|
||||
***Consejo:*** *Certbot también está integrado en el script de gestión. Puedes ejecutar el comando `x-ui` , luego elegir `Gestión de Certificados SSL`.*
|
||||
### Cloudflare
|
||||
|
||||
El script de gestión incluye una aplicación de certificado SSL integrada para Cloudflare. Para usar este script para solicitar un certificado, necesitas lo siguiente:
|
||||
|
||||
- Correo electrónico registrado en Cloudflare
|
||||
- Clave API Global de Cloudflare
|
||||
- El nombre de dominio debe estar resuelto al servidor actual a través de Cloudflare
|
||||
|
||||
**Cómo obtener la Clave API Global de Cloudflare:**
|
||||
|
||||
1. Ejecuta el comando `x-ui` en la terminal y elige `Certificado SSL de Cloudflare`.
|
||||
2. Visita el enlace: [Tokens de API de Cloudflare](https://dash.cloudflare.com/profile/api-tokens).
|
||||
3. Haz clic en "Ver Clave API Global" (consulta la captura de pantalla a continuación):
|
||||

|
||||
4. Es posible que necesites volver a autenticar tu cuenta. Después de eso, se mostrará la Clave API (consulta la captura de pantalla a continuación):
|
||||

|
||||
|
||||
Al utilizarlo, simplemente ingresa tu `nombre de dominio`, `correo electrónico` y `CLAVE API`. El diagrama es el siguiente:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
@@ -218,13 +242,18 @@ location /sub {
|
||||
- Ubuntu 20.04+
|
||||
- Debian 11+
|
||||
- CentOS 8+
|
||||
- OpenEuler 22.03+
|
||||
- Fedora 36+
|
||||
- Arch Linux
|
||||
- Parch Linux
|
||||
- Manjaro
|
||||
- Armbian
|
||||
- AlmaLinux 9+
|
||||
- Rockylinux 9+
|
||||
- AlmaLinux 8.0+
|
||||
- Rocky Linux 8+
|
||||
- Oracle Linux 8+
|
||||
- OpenSUSE Tubleweed
|
||||
- Amazon Linux 2023
|
||||
- Windows x64
|
||||
|
||||
## Arquitecturas y Dispositivos Compatibles
|
||||
|
||||
@@ -248,14 +277,18 @@ Nuestra plataforma ofrece compatibilidad con una amplia gama de arquitecturas y
|
||||
|
||||
## Idiomas
|
||||
|
||||
- Inglés
|
||||
- Farsi
|
||||
- Chino
|
||||
- Ruso
|
||||
- Vietnamita
|
||||
- Español
|
||||
- Indonesio
|
||||
- Ucraniano
|
||||
- English (inglés)
|
||||
- Persian (persa)
|
||||
- Traditional Chinese (chino tradicional)
|
||||
- Simplified Chinese (chino simplificado)
|
||||
- Japanese (japonés)
|
||||
- Russian (ruso)
|
||||
- Vietnamese (vietnamita)
|
||||
- Spanish (español)
|
||||
- Indonesian (indonesio)
|
||||
- Ukrainian (ucraniano)
|
||||
- Turkish (turco)
|
||||
- Português (Brazil) (portugués (Brasil))
|
||||
|
||||
|
||||
## Características
|
||||
@@ -281,11 +314,14 @@ Nuestra plataforma ofrece compatibilidad con una amplia gama de arquitecturas y
|
||||
<details>
|
||||
<summary>Haz clic para ver los detalles de la configuración predeterminada</summary>
|
||||
|
||||
### Nombre de Usuario & Contraseña & Ruta Base Web:
|
||||
### Nombre de usuario, Contraseña, Puerto y Ruta Base Web
|
||||
|
||||
Estos se generarán aleatoriamente si no los modificas.
|
||||
Si elige no modificar estas configuraciones, se generarán aleatoriamente (esto no se aplica a Docker).
|
||||
|
||||
- **Puerto:** el puerto predeterminado para el panel es `2053`
|
||||
**Configuraciones predeterminadas para Docker:**
|
||||
- **Nombre de usuario:** admin
|
||||
- **Contraseña:** admin
|
||||
- **Puerto:** 2053
|
||||
|
||||
### Gestión de la Base de Datos:
|
||||
|
||||
@@ -445,6 +481,7 @@ Ingresa el ID de chat de usuario en el campo de entrada número 4. Las cuentas d
|
||||
|
||||
#### Uso
|
||||
|
||||
- [Documentación de API](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
|
||||
- `/login` con `POST` datos de usuario: `{username: '', password: ''}` para iniciar sesión
|
||||
- `/panel/api/inbounds` base para las siguientes acciones:
|
||||
|
||||
@@ -474,9 +511,7 @@ Ingresa el ID de chat de usuario en el campo de entrada número 4. Las cuentas d
|
||||
- `client.password` para TROJAN
|
||||
- `client.email` para Shadowsocks
|
||||
|
||||
|
||||
- [Documentación de API](https://documenter.getpostman.com/view/16802678/2s9YkgD5jm)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415%26entityType%3Dcollection%26workspaceId%3D2cd38c01-c851-4a15-a972-f181c23359d9)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
|
||||
</details>
|
||||
|
||||
## Variables de Entorno
|
||||
|
||||
37
README.md
37
README.md
@@ -30,12 +30,12 @@
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
## Install Custom Version
|
||||
## Install legacy Version (we don't recommend)
|
||||
|
||||
To install your desired version, add the version to the end of the installation command. e.g., ver `v2.4.0`:
|
||||
To install your desired version, use following installation command. e.g., ver `v1.7.9`:
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.0
|
||||
VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## SSL Certificate
|
||||
@@ -54,6 +54,8 @@ To manage SSL certificates using ACME:
|
||||
- **Get SSL:** Obtain SSL certificates.
|
||||
- **Revoke:** Revoke existing SSL certificates.
|
||||
- **Force Renew:** Force renewal of SSL certificates.
|
||||
- **Show Existing Domains:** Display all domain certificates available on the server.
|
||||
- **Set Certificate Paths for the Panel:** Specify the certificate for your domain to be used by the panel.
|
||||
|
||||
### Certbot
|
||||
|
||||
@@ -169,6 +171,8 @@ systemctl restart x-ui
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Add ```--pull always``` flag to make docker automatically recreate container if a newer image is pulled. See https://docs.docker.com/reference/cli/docker/container/run/#pull for more info.
|
||||
|
||||
**OR**
|
||||
|
||||
```sh
|
||||
@@ -243,15 +247,18 @@ location /sub {
|
||||
- Ubuntu 20.04+
|
||||
- Debian 11+
|
||||
- CentOS 8+
|
||||
- OpenEuler 22.03+
|
||||
- Fedora 36+
|
||||
- Arch Linux
|
||||
- Parch Linux
|
||||
- Manjaro
|
||||
- Armbian
|
||||
- AlmaLinux 9+
|
||||
- Rocky Linux 9+
|
||||
- AlmaLinux 8.0+
|
||||
- Rocky Linux 8+
|
||||
- Oracle Linux 8+
|
||||
- OpenSUSE Tubleweed
|
||||
- Amazon Linux 2023
|
||||
- Windows x64
|
||||
|
||||
## Supported Architectures and Devices
|
||||
|
||||
@@ -278,8 +285,10 @@ Our platform offers compatibility with a diverse range of architectures and devi
|
||||
## Languages
|
||||
|
||||
- English
|
||||
- Farsi
|
||||
- Chinese
|
||||
- Persian
|
||||
- Traditional Chinese
|
||||
- Simplified Chinese
|
||||
- Japanese
|
||||
- Russian
|
||||
- Vietnamese
|
||||
- Spanish
|
||||
@@ -312,11 +321,14 @@ Our platform offers compatibility with a diverse range of architectures and devi
|
||||
<details>
|
||||
<summary>Click for default settings details</summary>
|
||||
|
||||
### Username & Password & webbasepath:
|
||||
### Username, Password, Port, and Web Base Path
|
||||
|
||||
These will be generated randomly if you skip modifying them.
|
||||
If you choose not to modify these settings, they will be generated randomly (this does not apply to Docker).
|
||||
|
||||
- **Port:** the default port for panel is `2053`
|
||||
**Default Settings for Docker:**
|
||||
- **Username:** admin
|
||||
- **Password:** admin
|
||||
- **Port:** 2053
|
||||
|
||||
### Database Management:
|
||||
|
||||
@@ -477,6 +489,7 @@ Enter the user ID in input field number 4. The Telegram accounts with this id wi
|
||||
|
||||
#### Usage
|
||||
|
||||
- [API Documentation](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
|
||||
- `/login` with `POST` user data: `{username: '', password: ''}` for login
|
||||
- `/panel/api/inbounds` base for following actions:
|
||||
|
||||
@@ -507,9 +520,7 @@ Enter the user ID in input field number 4. The Telegram accounts with this id wi
|
||||
- `client.password` for TROJAN
|
||||
- `client.email` for Shadowsocks
|
||||
|
||||
|
||||
- [API Documentation](https://documenter.getpostman.com/view/16802678/2s9YkgD5jm)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415%26entityType%3Dcollection%26workspaceId%3D2cd38c01-c851-4a15-a972-f181c23359d9)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
|
||||
</details>
|
||||
|
||||
## Environment Variables
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
> **Отказ от ответственности:** Этот проект предназначен только для личного обучения и общения. Пожалуйста, не используйте его в незаконных целях и не применяйте в производственной среде.
|
||||
|
||||
**Если этот проект оказался полезным для вас, вы можете оценить его, постативив звёздочку** :star2:
|
||||
**Если этот проект оказался полезным для вас, вы можете оценить его, поставив звёздочку** :star2:
|
||||
|
||||
<p align="left">
|
||||
<a href="https://buymeacoffee.com/mhsanaei" target="_blank">
|
||||
@@ -30,12 +30,12 @@
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
## Установка определённой версии
|
||||
## Установить старую версию (мы не рекомендуем)
|
||||
|
||||
Чтобы установить нужную вам версию, добавьте номер версии в конец команды установки. Например, `v2.4.0`:
|
||||
Чтобы установить желаемую версию, используйте следующую команду установки. Например, ver `v1.7.9`:
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.0
|
||||
VERSION=v1.7.9 && <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
## SSL Сертификат
|
||||
@@ -53,7 +53,9 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
||||
|
||||
- **Get SSL:** Получить SSL сертификаты.
|
||||
- **Revoke:** Отозвать существующие SSL сертификаты.
|
||||
- **Force Renew:** Принудительно превыпустить SSL сертификаты.
|
||||
- **Force Renew:** Принудительно перевыпустить SSL сертификаты.
|
||||
- **Show Existing Domains:** Отобразить все сертификаты доменов, доступные на сервере.
|
||||
- **Set Certificate Paths for the Panel:** Укажите сертификат для вашего домена, который будет использоваться панелью.
|
||||
|
||||
### Certbot
|
||||
|
||||
@@ -76,7 +78,7 @@ certbot renew --dry-run
|
||||
**Как получить глобальный API-ключ Cloudflare:**
|
||||
|
||||
1. Выполните команду `x-ui` в терминале, затем выберите `Cloudflare SSL Certificate`.
|
||||
2. Посетите ссылку: [Cloudflare API Tokens](https://dash.cloudflare.com/profile/api-tokens).
|
||||
2. Перейдите по ссылке: [Cloudflare API Tokens](https://dash.cloudflare.com/profile/api-tokens).
|
||||
3. Нажмите на "View Global API Key" (см. скриншот ниже):
|
||||

|
||||
4. Возможно, вам потребуется повторно пройти аутентификацию. После этого ключ API будет отображён (см. скриншот ниже):
|
||||
@@ -168,6 +170,8 @@ systemctl restart x-ui
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Добавьте параметр ```--pull always``` для автоматического обновления контейнера, когда публикуется новый образ. Подробности: https://docs.docker.com/reference/cli/docker/container/run/#pull
|
||||
|
||||
**ИЛИ**
|
||||
|
||||
```sh
|
||||
@@ -242,15 +246,18 @@ location /sub {
|
||||
- Ubuntu 20.04+
|
||||
- Debian 11+
|
||||
- CentOS 8+
|
||||
- OpenEuler 22.03+
|
||||
- Fedora 36+
|
||||
- Arch Linux
|
||||
- Parch Linux
|
||||
- Manjaro
|
||||
- Armbian
|
||||
- AlmaLinux 9+
|
||||
- Rocky Linux 9+
|
||||
- AlmaLinux 8.0+
|
||||
- Rocky Linux 8+
|
||||
- Oracle Linux 8+
|
||||
- OpenSUSE Tubleweed
|
||||
- Amazon Linux 2023
|
||||
- Windows x64
|
||||
|
||||
## Поддерживаемые архитектуры и устройства
|
||||
|
||||
@@ -276,15 +283,18 @@ location /sub {
|
||||
|
||||
## Языки
|
||||
|
||||
- Английский
|
||||
- Фарси
|
||||
- Китайский
|
||||
- Русский
|
||||
- Вьетнамский
|
||||
- Испанский
|
||||
- Индонезийский
|
||||
- Украинский
|
||||
- Турецкий
|
||||
- English (английский)
|
||||
- Persian (персидский)
|
||||
- Traditional Chinese (традиционный китайский)
|
||||
- Simplified Chinese (упрощенный китайский)
|
||||
- Japanese (японский)
|
||||
- Russian (русский)
|
||||
- Vietnamese (вьетнамский)
|
||||
- Spanish (испанский)
|
||||
- Indonesian (индонезийский)
|
||||
- Ukrainian (украинский)
|
||||
- Turkish (турецкий)
|
||||
- Português (Brazil) (португальский (Бразилия))
|
||||
|
||||
## Возможности
|
||||
|
||||
@@ -308,11 +318,14 @@ location /sub {
|
||||
<details>
|
||||
<summary>Нажмите для получения информации о настройках по умолчанию</summary>
|
||||
|
||||
### Имя пользователя и пароль & webbasepath:
|
||||
### Имя пользователя, Пароль, Порт и Web Base Path
|
||||
|
||||
Эти параметры будут сгенерированы случайным образом, если вы пропустите их изменение.
|
||||
Если вы не измените эти настройки, они будут сгенерированы случайным образом (это не относится к Docker).
|
||||
|
||||
- **Порт:** порт панели по умолчанию — `2053`
|
||||
**Настройки по умолчанию для Docker:**
|
||||
- **Имя пользователя:** admin
|
||||
- **Пароль:** admin
|
||||
- **Порт:** 2053
|
||||
|
||||
### Управление базой данных:
|
||||
|
||||
@@ -329,7 +342,7 @@ location /sub {
|
||||
- Выберите опцию `Reset Web Base Path`.
|
||||
|
||||
2. **Генерация или настройка пути:**
|
||||
- Путь будет случайным образом сгенерирован, или вы можете ввести пользовательский путь.
|
||||
- Путь будет сгенерирован случайным образом, или вы можете ввести собственный путь.
|
||||
|
||||
3. **Просмотр текущих настроек:**
|
||||
- Чтобы просмотреть текущие настройки, используйте команду `x-ui settings` в терминале или опцию `View Current Settings` в `x-ui`.
|
||||
@@ -430,7 +443,7 @@ WARP встроен, и дополнительная установка не т
|
||||
|
||||
- Периодические отчеты
|
||||
- Уведомления о входе
|
||||
- Уведомления о пороге CPU
|
||||
- Уведомления о пороге загруженности процессора
|
||||
- Уведомления о времени истечения и трафике заранее
|
||||
- Поддерживает меню отчетов клиента, если имя пользователя телеграм клиента добавлено в конфигурации пользователя
|
||||
- Поддержка отчета о трафике через Telegram, поиск по UUID (VMESS/VLESS) или паролю (TROJAN) - анонимно
|
||||
@@ -444,7 +457,7 @@ WARP встроен, и дополнительная установка не т
|
||||
|
||||
### Настройка телеграм-бота
|
||||
|
||||
- Запустить [Botfather](https://t.me/BotFather) в вашем аккаунте Telegram:
|
||||
- Запустите [Botfather](https://t.me/BotFather) в вашем аккаунте Telegram:
|
||||

|
||||
|
||||
- Создайте нового бота с помощью команды /newbot: у вас спросят 2 вопроса: отображаемое имя и имя пользователя для вашего бота. Обратите внимание, что имя пользователя должно заканчиваться на слово "bot".
|
||||
@@ -459,7 +472,7 @@ WARP встроен, и дополнительная установка не т
|
||||
Введите токен вашего бота в поле ввода номер 3.
|
||||
Введите ID пользователя в поле ввода номер 4. Telegram-аккаунты с этим ID будут администраторами бота. (Вы можете ввести несколько ID, разделяя их запятой)
|
||||
|
||||
- Как получить ID пользователя Telegram? Используйте этого [бота](https://t.me/useridinfobot). Запустите бота, и он предоставит вам ваше ID пользователя Telegram.
|
||||
- Как получить ID пользователя Telegram? Используйте этот [бот](https://t.me/useridinfobot). Запустите бота, и он отобразит ваш ID пользователя Telegram.
|
||||

|
||||
|
||||
</details>
|
||||
@@ -471,6 +484,7 @@ WARP встроен, и дополнительная установка не т
|
||||
|
||||
#### Использование
|
||||
|
||||
- [API документация](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
|
||||
- `/login` с `POST`-данными: `{username: '', password: ''}` для входа
|
||||
- `/panel/api/inbounds` это базовый путь для следующих действий:
|
||||
|
||||
@@ -493,7 +507,7 @@ WARP встроен, и дополнительная установка не т
|
||||
| `POST` | `"/resetAllTraffics"` | Сбросить трафик всех входящих соединений
|
||||
| `POST` | `"/resetAllClientTraffics/:id"` | Сбросить трафик всех клиентов в входящем соединении
|
||||
| `POST` | `"/delDepletedClients/:id"` | Удалить истекших клиентов в входящем соединении (-1: всех)
|
||||
| `POST` | `"/onlines"` | Получить пользователей, которые онлайн (список email'ов)
|
||||
| `POST` | `"/onlines"` | Получить пользователей, которые находятся онлайн (список email'ов)
|
||||
|
||||
\*- Поле `clientId` должно быть заполнено следующим образом:
|
||||
|
||||
@@ -504,8 +518,7 @@ WARP встроен, и дополнительная установка не т
|
||||
</details>
|
||||
|
||||
|
||||
- [API-документация](https://documenter.getpostman.com/view/16802678/2s9YkgD5jm)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415%26entityType%3Dcollection%26workspaceId%3D2cd38c01-c851-4a15-a972-f181c23359d9)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
|
||||
</details>
|
||||
|
||||
## Переменные среды
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
## 安装指定版本
|
||||
## 安装旧版本 (我们不建议)
|
||||
|
||||
要安装所需的版本,请将该版本添加到安装命令的末尾。 e.g., ver `v2.4.0`:
|
||||
要安装您想要的版本,请使用以下安装命令。例如,ver `v1.7.9`:
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.4.0
|
||||
VERSION=v1.7.9 && <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
|
||||
```
|
||||
|
||||
### SSL证书
|
||||
@@ -51,9 +51,11 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
||||
2. 在终端中运行 `x-ui` 命令,然后选择 `SSL证书管理`。
|
||||
3. 您将看到以下选项:
|
||||
|
||||
- **获取SSL证书:** 获取SSL证书。
|
||||
- **吊销:** 吊销现有的SSL证书。
|
||||
- **强制更新:** 强制更新SSL证书。
|
||||
- **Get SSL:** 获取SSL证书。
|
||||
- **Revoke:** 吊销现有的SSL证书。
|
||||
- **Force Renew:** 强制更新SSL证书。
|
||||
- **Show Existing Domains:** 显示服务器上所有可用的域证书。
|
||||
- **Set Certificate Paths for the Panel:** 指定用于面板的域证书。
|
||||
|
||||
### Certbot
|
||||
|
||||
@@ -241,13 +243,18 @@ location /sub {
|
||||
- Ubuntu 20.04+
|
||||
- Debian 11+
|
||||
- CentOS 8+
|
||||
- OpenEuler 22.03+
|
||||
- Fedora 36+
|
||||
- Arch Linux
|
||||
- Parch Linux
|
||||
- Manjaro
|
||||
- Armbian
|
||||
- AlmaLinux 9+
|
||||
- Rockylinux 9+
|
||||
- AlmaLinux 8.0+
|
||||
- Rocky Linux 8+
|
||||
- Oracle Linux 8+
|
||||
- OpenSUSE Tubleweed
|
||||
- Amazon Linux 2023
|
||||
- Windows x64
|
||||
|
||||
## 支持的架构和设备
|
||||
<details>
|
||||
@@ -270,14 +277,18 @@ location /sub {
|
||||
|
||||
## Languages
|
||||
|
||||
- English(英语)
|
||||
- Farsi(伊朗语)
|
||||
- Chinese(中文)
|
||||
- Russian(俄语)
|
||||
- Vietnamese(越南语)
|
||||
- Spanish(西班牙语)
|
||||
- Indonesian (印度尼西亚语)
|
||||
- Ukrainian(乌克兰语)
|
||||
- English(英语)
|
||||
- Persian(波斯语)
|
||||
- Traditional Chinese(繁体中文)
|
||||
- Simplified Chinese(简体中文)
|
||||
- Japanese(日语)
|
||||
- Russian(俄语)
|
||||
- Vietnamese(越南语)
|
||||
- Spanish(西班牙语)
|
||||
- Indonesian(印尼语)
|
||||
- Ukrainian(乌克兰语)
|
||||
- Turkish(土耳其语)
|
||||
- Português (Brazil)(葡萄牙语(巴西))
|
||||
|
||||
|
||||
## Features
|
||||
@@ -303,11 +314,14 @@ location /sub {
|
||||
<details>
|
||||
<summary>点击查看默认设置详情</summary>
|
||||
|
||||
### 用户名 & 密码 & Web基础路径:
|
||||
### 用户名、密码、端口和 Web Base Path
|
||||
|
||||
如果不修改这些,它们将会随机生成。
|
||||
如果您选择不修改这些设置,它们将随机生成(不适用于 Docker)。
|
||||
|
||||
- **端口号:** 面板的默认端口号是 `2053`
|
||||
**Docker 的默认设置:**
|
||||
- **用户名:** admin
|
||||
- **密码:** admin
|
||||
- **端口:** 2053
|
||||
|
||||
### 数据库管理:
|
||||
|
||||
@@ -467,6 +481,7 @@ Web 面板通过 Telegram Bot 支持每日流量、面板登录、数据库备
|
||||
|
||||
#### 使用
|
||||
|
||||
- [API 文档](https://www.postman.com/hsanaei/3x-ui/collection/q1l5l0u/3x-ui)
|
||||
- `/login` 使用 `POST` 用户名称 & 密码: `{username: '', password: ''}` 登录
|
||||
- `/panel/api/inbounds` 以下操作的基础:
|
||||
|
||||
@@ -496,9 +511,7 @@ Web 面板通过 Telegram Bot 支持每日流量、面板登录、数据库备
|
||||
- `client.password` TROJAN
|
||||
- `client.email` Shadowsocks
|
||||
|
||||
|
||||
- [API 文档](https://documenter.getpostman.com/view/16802678/2s9YkgD5jm)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D16802678-1a4c9270-ac77-40ed-959a-7aa56dc4a415%26entityType%3Dcollection%26workspaceId%3D2cd38c01-c851-4a15-a972-f181c23359d9)
|
||||
- [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://app.getpostman.com/run-collection/5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D5146551-dda3cab3-0e33-485f-96f9-d4262f437ac5%26entityType%3Dcollection%26workspaceId%3Dd64f609f-485a-4951-9b8f-876b3f917124)
|
||||
</details>
|
||||
|
||||
## 环境变量
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.4.0
|
||||
2.4.8
|
||||
@@ -46,6 +46,7 @@ type Inbound struct {
|
||||
StreamSettings string `json:"streamSettings" form:"streamSettings"`
|
||||
Tag string `json:"tag" form:"tag" gorm:"unique"`
|
||||
Sniffing string `json:"sniffing" form:"sniffing"`
|
||||
Allocate string `json:"allocate" form:"allocate"`
|
||||
}
|
||||
|
||||
type OutboundTraffics struct {
|
||||
@@ -75,6 +76,7 @@ func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig {
|
||||
StreamSettings: json_util.RawMessage(i.StreamSettings),
|
||||
Tag: i.Tag,
|
||||
Sniffing: json_util.RawMessage(i.Sniffing),
|
||||
Allocate: json_util.RawMessage(i.Allocate),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
84
go.mod
84
go.mod
@@ -1,46 +1,46 @@
|
||||
module x-ui
|
||||
|
||||
go 1.23.1
|
||||
go 1.23.3
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/gzip v1.0.1
|
||||
github.com/gin-contrib/sessions v1.0.1
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/goccy/go-json v0.10.3
|
||||
github.com/mymmrac/telego v0.31.2
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||
github.com/mymmrac/telego v0.31.4
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.1
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
github.com/pelletier/go-toml/v2 v2.2.3
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil/v4 v4.24.8
|
||||
github.com/valyala/fasthttp v1.55.0
|
||||
github.com/xtls/xray-core v1.8.24
|
||||
github.com/shirou/gopsutil/v4 v4.24.10
|
||||
github.com/valyala/fasthttp v1.57.0
|
||||
github.com/xtls/xray-core v1.8.25-0.20241121054707-513f18bf531e
|
||||
go.uber.org/atomic v1.11.0
|
||||
golang.org/x/text v0.18.0
|
||||
google.golang.org/grpc v1.66.0
|
||||
golang.org/x/text v0.20.0
|
||||
google.golang.org/grpc v1.68.0
|
||||
gorm.io/driver/sqlite v1.5.6
|
||||
gorm.io/gorm v1.25.11
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/bytedance/sonic v1.12.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||
github.com/cloudflare/circl v1.4.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/bytedance/sonic v1.12.4 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.5.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/ebitengine/purego v0.8.1 // indirect
|
||||
github.com/fasthttp/router v1.5.2 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.23.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9 // indirect
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 // indirect
|
||||
github.com/gorilla/context v1.1.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/gorilla/sessions v1.4.0 // indirect
|
||||
@@ -49,53 +49,53 @@ 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.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.23 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.24 // 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.20.2 // indirect
|
||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.47.0 // indirect
|
||||
github.com/quic-go/quic-go v0.48.1 // indirect
|
||||
github.com/refraction-networking/utls v1.6.7 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/sagernet/sing v0.4.2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/sagernet/sing v0.5.1 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/tklauser/numcpus v0.9.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
github.com/vishvananda/netlink v1.3.0 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/arch v0.10.0 // indirect
|
||||
golang.org/x/crypto v0.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
golang.org/x/arch v0.12.0 // indirect
|
||||
golang.org/x/crypto v0.29.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.31.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
golang.org/x/tools v0.27.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/protobuf v1.35.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
|
||||
336
go.sum
336
go.sum
@@ -1,52 +1,33 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
|
||||
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg=
|
||||
github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/bytedance/sonic v1.12.4 h1:9Csb3c9ZJhfUWeMtpCDCq6BUoH5ogfDFLUgQ/jG+R0k=
|
||||
github.com/bytedance/sonic v1.12.4/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
||||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY=
|
||||
github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
|
||||
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
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=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
|
||||
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/fasthttp/router v1.5.2 h1:ckJCCdV7hWkkrMeId3WfEhz+4Gyyf6QPwxi/RHIMZ6I=
|
||||
github.com/fasthttp/router v1.5.2/go.mod h1:C8EY53ozOwpONyevc/V7Gr8pqnEjwnkFFqPo1alAGs0=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
|
||||
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
|
||||
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
|
||||
@@ -57,8 +38,6 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
@@ -70,39 +49,25 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
|
||||
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/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-20240903155634-a8630aee4ab9 h1:q5g0N9eal4bmJwXHC5z0QCKs8qhS35hFfq0BAYsIwZI=
|
||||
github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
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=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||
github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
@@ -113,135 +78,82 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grbit/go-json v0.11.0 h1:bAbyMdYrYl/OjYsSqLH99N2DyQ291mHy726Mx+sYrnc=
|
||||
github.com/grbit/go-json v0.11.0/go.mod h1:IYpHsdybQ386+6g3VE6AXQ3uTGa5mquBme5/ZWmtzek=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY=
|
||||
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
|
||||
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mymmrac/telego v0.31.2 h1:srvQOQtb5ZswmqIr03VuAkIF076bi25n7fyQ51Ifstw=
|
||||
github.com/mymmrac/telego v0.31.2/go.mod h1:dyuyrOIagRstnm2ZNWuVilPdsslQyEgwYww9zkDqdJU=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/mymmrac/telego v0.31.4 h1:NpiNl0P/8eydknka/k6XaaaWVj5BKMlM3Ibba63QTBU=
|
||||
github.com/mymmrac/telego v0.31.4/go.mod h1:T12js1PgbYDYznvoN05MSMuPMfWTYo7D9LKl5cPFWiI=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
|
||||
github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
|
||||
github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
|
||||
github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
|
||||
github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM=
|
||||
github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v4 v4.24.8 h1:pVQjIenQkIhqO81mwTaXjTzOMT7d3TZkf43PlVFHENI=
|
||||
github.com/shirou/gopsutil/v4 v4.24.8/go.mod h1:wE0OrJtj4dG+hYkxqDH3QiBICdKSf04/npcvLLc/oRg=
|
||||
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=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/shirou/gopsutil/v4 v4.24.10 h1:7VOzPtfw/5YDU+jLEoBwXwxJbQetULywoSV4RYY7HkM=
|
||||
github.com/shirou/gopsutil/v4 v4.24.10/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -250,11 +162,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
|
||||
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
@@ -263,127 +174,68 @@ github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
|
||||
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
|
||||
github.com/valyala/fasthttp v1.57.0 h1:Xw8SjWGEP/+wAAgyy5XTvgrWlOD1+TxbbvNADYCm1Tg=
|
||||
github.com/valyala/fasthttp v1.57.0/go.mod h1:h6ZBaPRlzpZ6O3H5t2gEk1Qi33+TmLvfwgLLp0t9CpE=
|
||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/xtls/xray-core v1.8.24 h1:Y2NumdlnJ9C9gvh1Ivs2+73ui5XQgB70wZXYCiI9DyY=
|
||||
github.com/xtls/xray-core v1.8.24/go.mod h1:cWIOI6iBBOsB0HHU9PGhaiBhaMPfiktUjwA0IWolWJc=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
||||
github.com/xtls/xray-core v1.8.25-0.20241121054707-513f18bf531e h1:J5sTv0Sw+BonaI+rBh4Jkw9BfBqDjfAts81/HbIaqNg=
|
||||
github.com/xtls/xray-core v1.8.25-0.20241121054707-513f18bf531e/go.mod h1:wByClH1yrH8I611sREjG62gxbP5hFtdAWYJfydQF/zI=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/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.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=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
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.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8=
|
||||
golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
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=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
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=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.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=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
|
||||
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
|
||||
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
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.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.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-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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
|
||||
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
|
||||
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-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=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
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-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
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.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
||||
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -392,16 +244,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
|
||||
gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
||||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 h1:ze1vwAdliUAr68RQ5NtufWaXaOg8WUO2OACzEV+TNdE=
|
||||
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
||||
150
install.sh
150
install.sh
@@ -39,43 +39,53 @@ arch() {
|
||||
echo "arch: $(arch)"
|
||||
|
||||
os_version=""
|
||||
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||
os_version=$(grep "^VERSION_ID" /etc/os-release | cut -d '=' -f2 | tr -d '"' | tr -d '.')
|
||||
|
||||
if [[ "${release}" == "arch" ]]; then
|
||||
echo "Your OS is Arch Linux"
|
||||
elif [[ "${release}" == "parch" ]]; then
|
||||
echo "Your OS is Parch linux"
|
||||
echo "Your OS is Parch Linux"
|
||||
elif [[ "${release}" == "manjaro" ]]; then
|
||||
echo "Your OS is Manjaro"
|
||||
elif [[ "${release}" == "armbian" ]]; then
|
||||
echo "Your OS is Armbian"
|
||||
elif [[ "${release}" == "alpine" ]]; then
|
||||
echo "Your OS is Alpine Linux"
|
||||
elif [[ "${release}" == "opensuse-tumbleweed" ]]; then
|
||||
echo "Your OS is OpenSUSE Tumbleweed"
|
||||
elif [[ "${release}" == "openEuler" ]]; then
|
||||
if [[ ${os_version} -lt 2203 ]]; then
|
||||
echo -e "${red} Please use OpenEuler 22.03 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "centos" ]]; then
|
||||
if [[ ${os_version} -lt 8 ]]; then
|
||||
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "ubuntu" ]]; then
|
||||
if [[ ${os_version} -lt 20 ]]; then
|
||||
if [[ ${os_version} -lt 2004 ]]; then
|
||||
echo -e "${red} Please use Ubuntu 20 or higher version!${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "fedora" ]]; then
|
||||
if [[ ${os_version} -lt 36 ]]; then
|
||||
echo -e "${red} Please use Fedora 36 or higher version!${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "amzn" ]]; then
|
||||
if [[ ${os_version} != "2023" ]]; then
|
||||
echo -e "${red} Please use Amazon Linux 2023!${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "debian" ]]; then
|
||||
if [[ ${os_version} -lt 11 ]]; then
|
||||
echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "almalinux" ]]; then
|
||||
if [[ ${os_version} -lt 9 ]]; then
|
||||
echo -e "${red} Please use AlmaLinux 9 or higher ${plain}\n" && exit 1
|
||||
if [[ ${os_version} -lt 80 ]]; then
|
||||
echo -e "${red} Please use AlmaLinux 8.0 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "rocky" ]]; then
|
||||
if [[ ${os_version} -lt 9 ]]; then
|
||||
echo -e "${red} Please use Rocky Linux 9 or higher ${plain}\n" && exit 1
|
||||
if [[ ${os_version} -lt 8 ]]; then
|
||||
echo -e "${red} Please use Rocky Linux 8 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "oracle" ]]; then
|
||||
elif [[ "${release}" == "ol" ]]; then
|
||||
if [[ ${os_version} -lt 8 ]]; then
|
||||
echo -e "${red} Please use Oracle Linux 8 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
@@ -85,17 +95,18 @@ else
|
||||
echo "- Ubuntu 20.04+"
|
||||
echo "- Debian 11+"
|
||||
echo "- CentOS 8+"
|
||||
echo "- OpenEuler 22.03+"
|
||||
echo "- Fedora 36+"
|
||||
echo "- Arch Linux"
|
||||
echo "- Parch Linux"
|
||||
echo "- Manjaro"
|
||||
echo "- Armbian"
|
||||
echo "- AlmaLinux 9+"
|
||||
echo "- Rocky Linux 9+"
|
||||
echo "- AlmaLinux 8.0+"
|
||||
echo "- Rocky Linux 8+"
|
||||
echo "- Oracle Linux 8+"
|
||||
echo "- OpenSUSE Tumbleweed"
|
||||
echo "- Amazon Linux 2023"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
install_base() {
|
||||
@@ -103,10 +114,10 @@ install_base() {
|
||||
ubuntu | debian | armbian)
|
||||
apt-get update && apt-get install -y -q wget curl tar tzdata
|
||||
;;
|
||||
centos | almalinux | rocky | oracle)
|
||||
centos | almalinux | rocky | ol)
|
||||
yum -y update && yum install -y -q wget curl tar tzdata
|
||||
;;
|
||||
fedora)
|
||||
fedora | amzn)
|
||||
dnf -y update && dnf install -y -q wget curl tar tzdata
|
||||
;;
|
||||
arch | manjaro | parch)
|
||||
@@ -127,44 +138,63 @@ gen_random_string() {
|
||||
echo "$random_string"
|
||||
}
|
||||
|
||||
# This function will be called when user installed x-ui out of security
|
||||
config_after_install() {
|
||||
echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}"
|
||||
read -p "Would you like to customize the panel settings? (If not, random settings will be applied) [y/n]: " config_confirm
|
||||
if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
|
||||
read -p "Please set up your username: " config_account
|
||||
echo -e "${yellow}Your username will be: ${config_account}${plain}"
|
||||
read -p "Please set up your password: " config_password
|
||||
echo -e "${yellow}Your password will be: ${config_password}${plain}"
|
||||
read -p "Please set up the panel port: " config_port
|
||||
echo -e "${yellow}Your panel port is: ${config_port}${plain}"
|
||||
read -p "Please set up the web base path (ip:port/webbasepath/): " config_webBasePath
|
||||
echo -e "${yellow}Your web base path is: ${config_webBasePath}${plain}"
|
||||
echo -e "${yellow}Initializing, please wait...${plain}"
|
||||
/usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password}
|
||||
echo -e "${yellow}Account name and password set successfully!${plain}"
|
||||
/usr/local/x-ui/x-ui setting -port ${config_port}
|
||||
echo -e "${yellow}Panel port set successfully!${plain}"
|
||||
/usr/local/x-ui/x-ui setting -webBasePath ${config_webBasePath}
|
||||
echo -e "${yellow}Web base path set successfully!${plain}"
|
||||
else
|
||||
echo -e "${red}Cancel...${plain}"
|
||||
if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then
|
||||
local usernameTemp=$(head -c 6 /dev/urandom | base64)
|
||||
local passwordTemp=$(head -c 6 /dev/urandom | base64)
|
||||
local webBasePathTemp=$(gen_random_string 10)
|
||||
/usr/local/x-ui/x-ui setting -username ${usernameTemp} -password ${passwordTemp} -webBasePath ${webBasePathTemp}
|
||||
echo -e "This is a fresh installation, will generate random login info for security concerns:"
|
||||
local existing_username=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'username: .+' | awk '{print $2}')
|
||||
local existing_password=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'password: .+' | awk '{print $2}')
|
||||
local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
|
||||
local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
|
||||
local server_ip=$(curl -s https://api.ipify.org)
|
||||
|
||||
if [[ ${#existing_webBasePath} -lt 4 ]]; then
|
||||
if [[ "$existing_username" == "admin" && "$existing_password" == "admin" ]]; then
|
||||
local config_webBasePath=$(gen_random_string 15)
|
||||
local config_username=$(gen_random_string 10)
|
||||
local config_password=$(gen_random_string 10)
|
||||
|
||||
read -p "Would you like to customize the Panel Port settings? (If not, a random port will be applied) [y/n]: " config_confirm
|
||||
if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
|
||||
read -p "Please set up the panel port: " config_port
|
||||
echo -e "${yellow}Your Panel Port is: ${config_port}${plain}"
|
||||
else
|
||||
local config_port=$(shuf -i 1024-62000 -n 1)
|
||||
echo -e "${yellow}Generated random port: ${config_port}${plain}"
|
||||
fi
|
||||
|
||||
/usr/local/x-ui/x-ui setting -username "${config_username}" -password "${config_password}" -port "${config_port}" -webBasePath "${config_webBasePath}"
|
||||
echo -e "This is a fresh installation, generating random login info for security concerns:"
|
||||
echo -e "###############################################"
|
||||
echo -e "${green}Username: ${usernameTemp}${plain}"
|
||||
echo -e "${green}Password: ${passwordTemp}${plain}"
|
||||
echo -e "${green}WebBasePath: ${webBasePathTemp}${plain}"
|
||||
echo -e "${green}Username: ${config_username}${plain}"
|
||||
echo -e "${green}Password: ${config_password}${plain}"
|
||||
echo -e "${green}Port: ${config_port}${plain}"
|
||||
echo -e "${green}WebBasePath: ${config_webBasePath}${plain}"
|
||||
echo -e "${green}Access URL: http://${server_ip}:${config_port}/${config_webBasePath}${plain}"
|
||||
echo -e "###############################################"
|
||||
echo -e "${yellow}If you forgot your login info, you can type "x-ui settings" to check after installation${plain}"
|
||||
echo -e "${yellow}If you forgot your login info, you can type 'x-ui settings' to check${plain}"
|
||||
else
|
||||
echo -e "${yellow}This is your upgrade, will keep old settings. If you forgot your login info, you can type "x-ui settings" to check${plain}"
|
||||
local config_webBasePath=$(gen_random_string 15)
|
||||
echo -e "${yellow}WebBasePath is missing or too short. Generating a new one...${plain}"
|
||||
/usr/local/x-ui/x-ui setting -webBasePath "${config_webBasePath}"
|
||||
echo -e "${green}New WebBasePath: ${config_webBasePath}${plain}"
|
||||
echo -e "${green}Access URL: http://${server_ip}:${existing_port}/${config_webBasePath}${plain}"
|
||||
fi
|
||||
else
|
||||
if [[ "$existing_username" == "admin" && "$existing_password" == "admin" ]]; then
|
||||
local config_username=$(gen_random_string 10)
|
||||
local config_password=$(gen_random_string 10)
|
||||
|
||||
echo -e "${yellow}Default credentials detected. Security update required...${plain}"
|
||||
/usr/local/x-ui/x-ui setting -username "${config_username}" -password "${config_password}"
|
||||
echo -e "Generated new random login credentials:"
|
||||
echo -e "###############################################"
|
||||
echo -e "${green}Username: ${config_username}${plain}"
|
||||
echo -e "${green}Password: ${config_password}${plain}"
|
||||
echo -e "###############################################"
|
||||
echo -e "${yellow}If you forgot your login info, you can type 'x-ui settings' to check${plain}"
|
||||
else
|
||||
echo -e "${green}Username, Password, and WebBasePath are properly set. Exiting...${plain}"
|
||||
fi
|
||||
fi
|
||||
|
||||
/usr/local/x-ui/x-ui migrate
|
||||
}
|
||||
|
||||
@@ -172,24 +202,32 @@ install_x-ui() {
|
||||
cd /usr/local/
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
last_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [[ ! -n "$last_version" ]]; then
|
||||
echo -e "${red}Failed to fetch x-ui version, it maybe due to Github API restrictions, please try it later${plain}"
|
||||
tag_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [[ ! -n "$tag_version" ]]; then
|
||||
echo -e "${red}Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later${plain}"
|
||||
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/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch).tar.gz
|
||||
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
|
||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "${red}Downloading x-ui failed, please be sure that your server can access Github ${plain}"
|
||||
echo -e "${red}Downloading x-ui failed, please be sure that your server can access GitHub ${plain}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
last_version=$1
|
||||
url="https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch).tar.gz"
|
||||
tag_version=$1
|
||||
tag_version_numeric=${tag_version#v}
|
||||
min_version="2.3.5"
|
||||
|
||||
if [[ "$(printf '%s\n' "$min_version" "$tag_version_numeric" | sort -V | head -n1)" != "$min_version" ]]; then
|
||||
echo -e "${red}Please use a newer version (at least v2.3.5). Exiting installation.${plain}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
url="https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
|
||||
echo -e "Beginning to install x-ui $1"
|
||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch).tar.gz ${url}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "${red}Download x-ui $1 failed,please check the version exists ${plain}"
|
||||
echo -e "${red}Download x-ui $1 failed, please check if the version exists ${plain}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -220,7 +258,7 @@ install_x-ui() {
|
||||
systemctl daemon-reload
|
||||
systemctl enable x-ui
|
||||
systemctl start x-ui
|
||||
echo -e "${green}x-ui ${last_version}${plain} installation finished, it is running now..."
|
||||
echo -e "${green}x-ui ${tag_version}${plain} installation finished, it is running now..."
|
||||
echo -e ""
|
||||
echo -e "x-ui control menu usages: "
|
||||
echo -e "----------------------------------------------"
|
||||
@@ -236,7 +274,7 @@ install_x-ui() {
|
||||
echo -e "x-ui log - Check logs"
|
||||
echo -e "x-ui banlog - Check Fail2ban ban logs"
|
||||
echo -e "x-ui update - Update"
|
||||
echo -e "x-ui custom - custom version"
|
||||
echo -e "x-ui legacy - legacy version"
|
||||
echo -e "x-ui install - Install"
|
||||
echo -e "x-ui uninstall - Uninstall"
|
||||
echo -e "----------------------------------------------"
|
||||
|
||||
77
main.go
77
main.go
@@ -136,6 +136,15 @@ func showSetting(show bool) {
|
||||
fmt.Println("get webBasePath failed, error info:", err)
|
||||
}
|
||||
|
||||
certFile, err := settingService.GetCertFile()
|
||||
if err != nil {
|
||||
fmt.Println("get cert file failed, error info:", err)
|
||||
}
|
||||
keyFile, err := settingService.GetKeyFile()
|
||||
if err != nil {
|
||||
fmt.Println("get key file failed, error info:", err)
|
||||
}
|
||||
|
||||
userService := service.UserService{}
|
||||
userModel, err := userService.GetFirstUser()
|
||||
if err != nil {
|
||||
@@ -149,14 +158,15 @@ func showSetting(show bool) {
|
||||
}
|
||||
|
||||
fmt.Println("current panel settings as follows:")
|
||||
if certFile == "" || keyFile == "" {
|
||||
fmt.Println("Warning: Panel is not secure with SSL")
|
||||
} else {
|
||||
fmt.Println("Panel is secure with SSL")
|
||||
}
|
||||
fmt.Println("username:", username)
|
||||
fmt.Println("password:", userpasswd)
|
||||
fmt.Println("port:", port)
|
||||
if webBasePath != "" {
|
||||
fmt.Println("webBasePath:", webBasePath)
|
||||
} else {
|
||||
fmt.Println("webBasePath is not set")
|
||||
}
|
||||
fmt.Println("webBasePath:", webBasePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +226,7 @@ func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime stri
|
||||
}
|
||||
}
|
||||
|
||||
func updateSetting(port int, username string, password string, webBasePath string) {
|
||||
func updateSetting(port int, username string, password string, webBasePath string, listenIP string) {
|
||||
err := database.InitDB(config.GetDBPath())
|
||||
if err != nil {
|
||||
fmt.Println("Database initialization failed:", err)
|
||||
@@ -252,6 +262,15 @@ func updateSetting(port int, username string, password string, webBasePath strin
|
||||
fmt.Println("Base URI path set successfully")
|
||||
}
|
||||
}
|
||||
|
||||
if listenIP != "" {
|
||||
err := settingService.SetListen(listenIP)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to set listen IP:", err)
|
||||
} else {
|
||||
fmt.Printf("listen %v set successfully", listenIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateCert(publicKey string, privateKey string) {
|
||||
@@ -281,6 +300,37 @@ func updateCert(publicKey string, privateKey string) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetCertificate(getCert bool) {
|
||||
if getCert {
|
||||
settingService := service.SettingService{}
|
||||
certFile, err := settingService.GetCertFile()
|
||||
if err != nil {
|
||||
fmt.Println("get cert file failed, error info:", err)
|
||||
}
|
||||
keyFile, err := settingService.GetKeyFile()
|
||||
if err != nil {
|
||||
fmt.Println("get key file failed, error info:", err)
|
||||
}
|
||||
|
||||
fmt.Println("cert:", certFile)
|
||||
fmt.Println("key:", keyFile)
|
||||
}
|
||||
}
|
||||
|
||||
func GetListenIP(getListen bool) {
|
||||
if getListen {
|
||||
|
||||
settingService := service.SettingService{}
|
||||
ListenIP, err := settingService.GetListen()
|
||||
if err != nil {
|
||||
log.Printf("Failed to retrieve listen IP: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("listenIP:", ListenIP)
|
||||
}
|
||||
}
|
||||
|
||||
func migrateDb() {
|
||||
inboundService := service.InboundService{}
|
||||
|
||||
@@ -339,6 +389,8 @@ func main() {
|
||||
var username string
|
||||
var password string
|
||||
var webBasePath string
|
||||
var listenIP string
|
||||
var getListen bool
|
||||
var webCertFile string
|
||||
var webKeyFile string
|
||||
var tgbottoken string
|
||||
@@ -347,6 +399,7 @@ func main() {
|
||||
var tgbotRuntime string
|
||||
var reset bool
|
||||
var show bool
|
||||
var getCert bool
|
||||
var remove_secret bool
|
||||
settingCmd.BoolVar(&reset, "reset", false, "Reset all settings")
|
||||
settingCmd.BoolVar(&show, "show", false, "Display current settings")
|
||||
@@ -355,6 +408,9 @@ func main() {
|
||||
settingCmd.StringVar(&username, "username", "", "Set login username")
|
||||
settingCmd.StringVar(&password, "password", "", "Set login password")
|
||||
settingCmd.StringVar(&webBasePath, "webBasePath", "", "Set base path for Panel")
|
||||
settingCmd.StringVar(&listenIP, "listenIP", "", "set panel listenIP IP")
|
||||
settingCmd.BoolVar(&getListen, "getListen", false, "Display current panel listenIP IP")
|
||||
settingCmd.BoolVar(&getCert, "getCert", false, "Display current certificate settings")
|
||||
settingCmd.StringVar(&webCertFile, "webCert", "", "Set path to public key file for panel")
|
||||
settingCmd.StringVar(&webKeyFile, "webCertKey", "", "Set path to private key file for panel")
|
||||
settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "Set token for Telegram bot")
|
||||
@@ -397,11 +453,17 @@ func main() {
|
||||
if reset {
|
||||
resetSetting()
|
||||
} else {
|
||||
updateSetting(port, username, password, webBasePath)
|
||||
updateSetting(port, username, password, webBasePath, listenIP)
|
||||
}
|
||||
if show {
|
||||
showSetting(show)
|
||||
}
|
||||
if getListen {
|
||||
GetListenIP(getListen)
|
||||
}
|
||||
if getCert {
|
||||
GetCertificate(getCert)
|
||||
}
|
||||
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
|
||||
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
|
||||
}
|
||||
@@ -422,7 +484,6 @@ func main() {
|
||||
} else {
|
||||
updateCert(webCertFile, webKeyFile)
|
||||
}
|
||||
|
||||
default:
|
||||
fmt.Println("Invalid subcommands")
|
||||
fmt.Println()
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls",
|
||||
"quic",
|
||||
"fakedns"
|
||||
],
|
||||
"enabled": true
|
||||
@@ -46,7 +47,9 @@
|
||||
"tag": "direct",
|
||||
"protocol": "freedom",
|
||||
"settings": {
|
||||
"domainStrategy": "UseIP"
|
||||
"domainStrategy": "AsIs",
|
||||
"redirect": "",
|
||||
"noises": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -92,9 +92,9 @@ func (s *Server) initRouter() (*gin.Engine, error) {
|
||||
SubJsonFragment = ""
|
||||
}
|
||||
|
||||
SubJsonNoise, err := s.settingService.GetSubJsonNoise()
|
||||
SubJsonNoises, err := s.settingService.GetSubJsonNoises()
|
||||
if err != nil {
|
||||
SubJsonNoise = ""
|
||||
SubJsonNoises = ""
|
||||
}
|
||||
|
||||
SubJsonMux, err := s.settingService.GetSubJsonMux()
|
||||
@@ -111,7 +111,7 @@ func (s *Server) initRouter() (*gin.Engine, error) {
|
||||
|
||||
s.sub = NewSUBController(
|
||||
g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates,
|
||||
SubJsonFragment, SubJsonNoise, SubJsonMux, SubJsonRules)
|
||||
SubJsonFragment, SubJsonNoises, SubJsonMux, SubJsonRules)
|
||||
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ type SubJsonService struct {
|
||||
configJson map[string]interface{}
|
||||
defaultOutbounds []json_util.RawMessage
|
||||
fragment string
|
||||
noise string
|
||||
noises string
|
||||
mux string
|
||||
|
||||
inboundService service.InboundService
|
||||
SubService *SubService
|
||||
}
|
||||
|
||||
func NewSubJsonService(fragment string, noise string, mux string, rules string, subService *SubService) *SubJsonService {
|
||||
func NewSubJsonService(fragment string, noises string, mux string, rules string, subService *SubService) *SubJsonService {
|
||||
var configJson map[string]interface{}
|
||||
var defaultOutbounds []json_util.RawMessage
|
||||
json.Unmarshal([]byte(defaultJson), &configJson)
|
||||
@@ -53,15 +53,15 @@ func NewSubJsonService(fragment string, noise string, mux string, rules string,
|
||||
defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(fragment))
|
||||
}
|
||||
|
||||
if noise != "" {
|
||||
defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(noise))
|
||||
if noises != "" {
|
||||
defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(noises))
|
||||
}
|
||||
|
||||
return &SubJsonService{
|
||||
configJson: configJson,
|
||||
defaultOutbounds: defaultOutbounds,
|
||||
fragment: fragment,
|
||||
noise: noise,
|
||||
noises: noises,
|
||||
mux: mux,
|
||||
SubService: subService,
|
||||
}
|
||||
|
||||
@@ -238,6 +238,7 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
||||
headers, _ := splithttp["headers"].(map[string]interface{})
|
||||
obj["host"] = searchHost(headers)
|
||||
}
|
||||
obj["mode"] = splithttp["mode"].(string)
|
||||
}
|
||||
security, _ := stream["security"].(string)
|
||||
obj["tls"] = security
|
||||
@@ -389,6 +390,7 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
||||
headers, _ := splithttp["headers"].(map[string]interface{})
|
||||
params["host"] = searchHost(headers)
|
||||
}
|
||||
params["mode"] = splithttp["mode"].(string)
|
||||
}
|
||||
security, _ := stream["security"].(string)
|
||||
if security == "tls" {
|
||||
@@ -452,38 +454,7 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
||||
}
|
||||
}
|
||||
|
||||
if security == "xtls" {
|
||||
params["security"] = "xtls"
|
||||
xtlsSetting, _ := stream["xtlsSettings"].(map[string]interface{})
|
||||
alpns, _ := xtlsSetting["alpn"].([]interface{})
|
||||
var alpn []string
|
||||
for _, a := range alpns {
|
||||
alpn = append(alpn, a.(string))
|
||||
}
|
||||
if len(alpn) > 0 {
|
||||
params["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if sniValue, ok := searchKey(xtlsSetting, "serverName"); ok {
|
||||
params["sni"], _ = sniValue.(string)
|
||||
}
|
||||
xtlsSettings, _ := searchKey(xtlsSetting, "settings")
|
||||
if xtlsSetting != nil {
|
||||
if fpValue, ok := searchKey(xtlsSettings, "fingerprint"); ok {
|
||||
params["fp"], _ = fpValue.(string)
|
||||
}
|
||||
if insecure, ok := searchKey(xtlsSettings, "allowInsecure"); ok {
|
||||
if insecure.(bool) {
|
||||
params["allowInsecure"] = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
|
||||
params["flow"] = clients[clientIndex].Flow
|
||||
}
|
||||
}
|
||||
|
||||
if security != "tls" && security != "reality" && security != "xtls" {
|
||||
if security != "tls" && security != "reality" {
|
||||
params["security"] = "none"
|
||||
}
|
||||
|
||||
@@ -617,6 +588,7 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
||||
headers, _ := splithttp["headers"].(map[string]interface{})
|
||||
params["host"] = searchHost(headers)
|
||||
}
|
||||
params["mode"] = splithttp["mode"].(string)
|
||||
}
|
||||
security, _ := stream["security"].(string)
|
||||
if security == "tls" {
|
||||
@@ -676,39 +648,7 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
||||
}
|
||||
}
|
||||
|
||||
if security == "xtls" {
|
||||
params["security"] = "xtls"
|
||||
xtlsSetting, _ := stream["xtlsSettings"].(map[string]interface{})
|
||||
alpns, _ := xtlsSetting["alpn"].([]interface{})
|
||||
var alpn []string
|
||||
for _, a := range alpns {
|
||||
alpn = append(alpn, a.(string))
|
||||
}
|
||||
if len(alpn) > 0 {
|
||||
params["alpn"] = strings.Join(alpn, ",")
|
||||
}
|
||||
if sniValue, ok := searchKey(xtlsSetting, "serverName"); ok {
|
||||
params["sni"], _ = sniValue.(string)
|
||||
}
|
||||
|
||||
xtlsSettings, _ := searchKey(xtlsSetting, "settings")
|
||||
if xtlsSetting != nil {
|
||||
if fpValue, ok := searchKey(xtlsSettings, "fingerprint"); ok {
|
||||
params["fp"], _ = fpValue.(string)
|
||||
}
|
||||
if insecure, ok := searchKey(xtlsSettings, "allowInsecure"); ok {
|
||||
if insecure.(bool) {
|
||||
params["allowInsecure"] = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
|
||||
params["flow"] = clients[clientIndex].Flow
|
||||
}
|
||||
}
|
||||
|
||||
if security != "tls" && security != "reality" && security != "xtls" {
|
||||
if security != "tls" && security != "reality" {
|
||||
params["security"] = "none"
|
||||
}
|
||||
|
||||
@@ -846,6 +786,7 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
|
||||
headers, _ := splithttp["headers"].(map[string]interface{})
|
||||
params["host"] = searchHost(headers)
|
||||
}
|
||||
params["mode"] = splithttp["mode"].(string)
|
||||
}
|
||||
|
||||
security, _ := stream["security"].(string)
|
||||
|
||||
@@ -4,18 +4,14 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func FormatTraffic(trafficBytes int64) (size string) {
|
||||
if trafficBytes < 1024 {
|
||||
return fmt.Sprintf("%.2fB", float64(trafficBytes)/float64(1))
|
||||
} else if trafficBytes < (1024 * 1024) {
|
||||
return fmt.Sprintf("%.2fKB", float64(trafficBytes)/float64(1024))
|
||||
} else if trafficBytes < (1024 * 1024 * 1024) {
|
||||
return fmt.Sprintf("%.2fMB", float64(trafficBytes)/float64(1024*1024))
|
||||
} else if trafficBytes < (1024 * 1024 * 1024 * 1024) {
|
||||
return fmt.Sprintf("%.2fGB", float64(trafficBytes)/float64(1024*1024*1024))
|
||||
} else if trafficBytes < (1024 * 1024 * 1024 * 1024 * 1024) {
|
||||
return fmt.Sprintf("%.2fTB", float64(trafficBytes)/float64(1024*1024*1024*1024))
|
||||
} else {
|
||||
return fmt.Sprintf("%.2fEB", float64(trafficBytes)/float64(1024*1024*1024*1024*1024))
|
||||
func FormatTraffic(trafficBytes int64) string {
|
||||
units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
|
||||
unitIndex := 0
|
||||
size := float64(trafficBytes)
|
||||
|
||||
for size >= 1024 && unitIndex < len(units)-1 {
|
||||
size /= 1024
|
||||
unitIndex++
|
||||
}
|
||||
return fmt.Sprintf("%.2f%s", size, units[unitIndex])
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
return scriptHint(editor, javascriptKeywords,
|
||||
function (e, cur) {return e.getTokenAt(cur);},
|
||||
options);
|
||||
};
|
||||
}
|
||||
CodeMirror.registerHelper("hint", "javascript", javascriptHint);
|
||||
|
||||
function getCoffeeScriptToken(editor, cur) {
|
||||
|
||||
@@ -362,7 +362,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.CodeMirror-lint-tooltip {
|
||||
background-color: #ffd;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
border-radius: 4px;
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
|
||||
@@ -1,93 +1,103 @@
|
||||
const supportLangs = [
|
||||
{
|
||||
name: 'English',
|
||||
value: 'en-US',
|
||||
icon: '🇺🇸',
|
||||
},
|
||||
{
|
||||
name: 'فارسی',
|
||||
value: 'fa-IR',
|
||||
icon: '🇮🇷',
|
||||
},
|
||||
{
|
||||
name: '中文',
|
||||
value: 'zh-CN',
|
||||
icon: '🇨🇳',
|
||||
},
|
||||
{
|
||||
name: 'Русский',
|
||||
value: 'ru-RU',
|
||||
icon: '🇷🇺',
|
||||
},
|
||||
{
|
||||
name: 'Tiếng Việt',
|
||||
value: 'vi-VN',
|
||||
icon: '🇻🇳',
|
||||
},
|
||||
{
|
||||
name: 'Español',
|
||||
value: 'es-ES',
|
||||
icon: '🇪🇸',
|
||||
},
|
||||
{
|
||||
name: 'Indonesian',
|
||||
value: 'id-ID',
|
||||
icon: '🇮🇩',
|
||||
},
|
||||
{
|
||||
name: 'Український',
|
||||
value: 'uk-UA',
|
||||
icon: '🇺🇦',
|
||||
},
|
||||
{
|
||||
name: 'Türkçe',
|
||||
value: 'tr-TR',
|
||||
icon: '🇹🇷',
|
||||
},
|
||||
{
|
||||
name: "Português",
|
||||
value: "pt-BR",
|
||||
icon: "🇧🇷",
|
||||
},
|
||||
{
|
||||
name: "English",
|
||||
value: "en-US",
|
||||
icon: "🇺🇸",
|
||||
},
|
||||
{
|
||||
name: "فارسی",
|
||||
value: "fa-IR",
|
||||
icon: "🇮🇷",
|
||||
},
|
||||
{
|
||||
name: "简体中文",
|
||||
value: "zh-CN",
|
||||
icon: "🇨🇳",
|
||||
},
|
||||
{
|
||||
name: "繁體中文",
|
||||
value: "zh-TW",
|
||||
icon: "🇹🇼",
|
||||
},
|
||||
{
|
||||
name: "日本語",
|
||||
value: "ja-JP",
|
||||
icon: "🇯🇵",
|
||||
},
|
||||
{
|
||||
name: "Русский",
|
||||
value: "ru-RU",
|
||||
icon: "🇷🇺",
|
||||
},
|
||||
{
|
||||
name: "Tiếng Việt",
|
||||
value: "vi-VN",
|
||||
icon: "🇻🇳",
|
||||
},
|
||||
{
|
||||
name: "Español",
|
||||
value: "es-ES",
|
||||
icon: "🇪🇸",
|
||||
},
|
||||
{
|
||||
name: "Indonesian",
|
||||
value: "id-ID",
|
||||
icon: "🇮🇩",
|
||||
},
|
||||
{
|
||||
name: "Український",
|
||||
value: "uk-UA",
|
||||
icon: "🇺🇦",
|
||||
},
|
||||
{
|
||||
name: "Türkçe",
|
||||
value: "tr-TR",
|
||||
icon: "🇹🇷",
|
||||
},
|
||||
{
|
||||
name: "Português",
|
||||
value: "pt-BR",
|
||||
icon: "🇧🇷",
|
||||
},
|
||||
];
|
||||
|
||||
function getLang() {
|
||||
let lang = getCookie('lang');
|
||||
let lang = getCookie("lang");
|
||||
|
||||
if (!lang) {
|
||||
if (window.navigator) {
|
||||
lang = window.navigator.language || window.navigator.userLanguage;
|
||||
if (!lang) {
|
||||
if (window.navigator) {
|
||||
lang = window.navigator.language || window.navigator.userLanguage;
|
||||
|
||||
if (isSupportLang(lang)) {
|
||||
setCookie('lang', lang, 150);
|
||||
} else {
|
||||
setCookie('lang', 'en-US', 150);
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
setCookie('lang', 'en-US', 150);
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
if (isSupportLang(lang)) {
|
||||
setCookie("lang", lang, 150);
|
||||
} else {
|
||||
setCookie("lang", "en-US", 150);
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
setCookie("lang", "en-US", 150);
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
return lang;
|
||||
return lang;
|
||||
}
|
||||
|
||||
function setLang(lang) {
|
||||
if (!isSupportLang(lang)) {
|
||||
lang = 'en-US';
|
||||
}
|
||||
if (!isSupportLang(lang)) {
|
||||
lang = "en-US";
|
||||
}
|
||||
|
||||
setCookie('lang', lang, 150);
|
||||
window.location.reload();
|
||||
setCookie("lang", lang, 150);
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function isSupportLang(lang) {
|
||||
for (l of supportLangs) {
|
||||
if (l.value === lang) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (l of supportLangs) {
|
||||
if (l.value === lang) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -140,9 +140,9 @@ class DBInbound {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
genInboundLinks(remarkModel) {
|
||||
|
||||
genInboundLinks(remarkModel) {
|
||||
const inbound = this.toInbound();
|
||||
return inbound.genInboundLinks(this.remark,remarkModel);
|
||||
return inbound.genInboundLinks(this.remark, remarkModel);
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,6 @@ const SSMethods = {
|
||||
BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305',
|
||||
};
|
||||
|
||||
const XTLS_FLOW_CONTROL = {
|
||||
ORIGIN: "xtls-rprx-origin",
|
||||
DIRECT: "xtls-rprx-direct",
|
||||
};
|
||||
|
||||
const TLS_FLOW_CONTROL = {
|
||||
VISION: "xtls-rprx-vision",
|
||||
VISION_UDP443: "xtls-rprx-vision-udp443",
|
||||
@@ -118,9 +113,14 @@ const USERS_SECURITY = {
|
||||
ZERO: "zero",
|
||||
};
|
||||
|
||||
const MODE_OPTION = {
|
||||
AUTO: "auto",
|
||||
PACKET_UP: "packet-up",
|
||||
STREAM_UP: "stream-up",
|
||||
};
|
||||
|
||||
Object.freeze(Protocols);
|
||||
Object.freeze(SSMethods);
|
||||
Object.freeze(XTLS_FLOW_CONTROL);
|
||||
Object.freeze(TLS_FLOW_CONTROL);
|
||||
Object.freeze(TLS_VERSION_OPTION);
|
||||
Object.freeze(TLS_CIPHER_OPTION);
|
||||
@@ -131,6 +131,7 @@ Object.freeze(USAGE_OPTION);
|
||||
Object.freeze(DOMAIN_STRATEGY_OPTION);
|
||||
Object.freeze(TCP_CONGESTION_OPTION);
|
||||
Object.freeze(USERS_SECURITY);
|
||||
Object.freeze(MODE_OPTION);
|
||||
|
||||
class XrayCommonClass {
|
||||
|
||||
@@ -529,6 +530,14 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
|
||||
scMinPostsIntervalMs = "10-50",
|
||||
noSSEHeader = false,
|
||||
xPaddingBytes = "100-1000",
|
||||
xmux = {
|
||||
maxConcurrency: "16-32",
|
||||
maxConnections: 0,
|
||||
cMaxReuseTimes: "64-128",
|
||||
cMaxLifetimeMs: 0
|
||||
},
|
||||
mode = MODE_OPTION.AUTO,
|
||||
noGRPCHeader = false,
|
||||
) {
|
||||
super();
|
||||
this.path = path;
|
||||
@@ -539,6 +548,9 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
|
||||
this.scMinPostsIntervalMs = scMinPostsIntervalMs;
|
||||
this.noSSEHeader = noSSEHeader;
|
||||
this.xPaddingBytes = xPaddingBytes;
|
||||
this.xmux = xmux;
|
||||
this.mode = mode;
|
||||
this.noGRPCHeader = noGRPCHeader;
|
||||
}
|
||||
|
||||
addHeader(name, value) {
|
||||
@@ -559,6 +571,9 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
|
||||
json.scMinPostsIntervalMs,
|
||||
json.noSSEHeader,
|
||||
json.xPaddingBytes,
|
||||
json.xmux,
|
||||
json.mode,
|
||||
json.noGRPCHeader
|
||||
);
|
||||
}
|
||||
|
||||
@@ -572,6 +587,14 @@ class SplitHTTPStreamSettings extends XrayCommonClass {
|
||||
scMinPostsIntervalMs: this.scMinPostsIntervalMs,
|
||||
noSSEHeader: this.noSSEHeader,
|
||||
xPaddingBytes: this.xPaddingBytes,
|
||||
xmux: {
|
||||
maxConcurrency: this.xmux.maxConcurrency,
|
||||
maxConnections: this.xmux.maxConnections,
|
||||
cMaxReuseTimes: this.xmux.cMaxReuseTimes,
|
||||
cMaxLifetimeMs: this.xmux.cMaxLifetimeMs
|
||||
},
|
||||
mode: this.mode,
|
||||
noGRPCHeader: this.noGRPCHeader
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -741,137 +764,6 @@ TlsStreamSettings.Settings = class extends XrayCommonClass {
|
||||
}
|
||||
};
|
||||
|
||||
class XtlsStreamSettings extends XrayCommonClass {
|
||||
constructor(
|
||||
serverName = '',
|
||||
certificates = [new XtlsStreamSettings.Cert()],
|
||||
alpn = [ALPN_OPTION.H3, ALPN_OPTION.H2, ALPN_OPTION.HTTP1],
|
||||
settings = new XtlsStreamSettings.Settings()
|
||||
) {
|
||||
super();
|
||||
this.sni = serverName;
|
||||
this.certs = certificates;
|
||||
this.alpn = alpn;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
addCert() {
|
||||
this.certs.push(new XtlsStreamSettings.Cert());
|
||||
}
|
||||
|
||||
removeCert(index) {
|
||||
this.certs.splice(index, 1);
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
let certs;
|
||||
let settings;
|
||||
if (!ObjectUtil.isEmpty(json.certificates)) {
|
||||
certs = json.certificates.map(cert => XtlsStreamSettings.Cert.fromJson(cert));
|
||||
}
|
||||
|
||||
if (!ObjectUtil.isEmpty(json.settings)) {
|
||||
settings = new XtlsStreamSettings.Settings(json.settings.allowInsecure, json.settings.serverName);
|
||||
}
|
||||
return new XtlsStreamSettings(
|
||||
json.serverName,
|
||||
certs,
|
||||
json.alpn,
|
||||
settings,
|
||||
);
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
serverName: this.sni,
|
||||
certificates: XtlsStreamSettings.toJsonArray(this.certs),
|
||||
alpn: this.alpn,
|
||||
settings: this.settings,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
XtlsStreamSettings.Cert = class extends XrayCommonClass {
|
||||
constructor(
|
||||
useFile = true,
|
||||
certificateFile = '',
|
||||
keyFile = '',
|
||||
certificate = '',
|
||||
key = '',
|
||||
ocspStapling = 3600,
|
||||
oneTimeLoading = false,
|
||||
usage = USAGE_OPTION.ENCIPHERMENT
|
||||
) {
|
||||
super();
|
||||
this.useFile = useFile;
|
||||
this.certFile = certificateFile;
|
||||
this.keyFile = keyFile;
|
||||
this.cert = Array.isArray(certificate) ? certificate.join('\n') : certificate;
|
||||
this.key = Array.isArray(key) ? key.join('\n') : key;
|
||||
this.ocspStapling = ocspStapling;
|
||||
this.oneTimeLoading = oneTimeLoading;
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
if ('certificateFile' in json && 'keyFile' in json) {
|
||||
return new XtlsStreamSettings.Cert(
|
||||
true,
|
||||
json.certificateFile,
|
||||
json.keyFile, '', '',
|
||||
json.ocspStapling,
|
||||
json.oneTimeLoading,
|
||||
json.usage,
|
||||
);
|
||||
} else {
|
||||
return new XtlsStreamSettings.Cert(
|
||||
false, '', '',
|
||||
json.certificate.join('\n'),
|
||||
json.key.join('\n'),
|
||||
json.ocspStapling,
|
||||
json.oneTimeLoading,
|
||||
json.usage,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toJson() {
|
||||
if (this.useFile) {
|
||||
return {
|
||||
certificateFile: this.certFile,
|
||||
keyFile: this.keyFile,
|
||||
ocspStapling: this.ocspStapling,
|
||||
oneTimeLoading: this.oneTimeLoading,
|
||||
usage: this.usage,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
certificate: this.cert.split('\n'),
|
||||
key: this.key.split('\n'),
|
||||
ocspStapling: this.ocspStapling,
|
||||
oneTimeLoading: this.oneTimeLoading,
|
||||
usage: this.usage,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
XtlsStreamSettings.Settings = class extends XrayCommonClass {
|
||||
constructor(allowInsecure = false) {
|
||||
super();
|
||||
this.allowInsecure = allowInsecure;
|
||||
}
|
||||
static fromJson(json = {}) {
|
||||
return new XtlsStreamSettings.Settings(
|
||||
json.allowInsecure,
|
||||
);
|
||||
}
|
||||
toJson() {
|
||||
return {
|
||||
allowInsecure: this.allowInsecure,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class RealityStreamSettings extends XrayCommonClass {
|
||||
constructor(
|
||||
@@ -895,7 +787,7 @@ class RealityStreamSettings extends XrayCommonClass {
|
||||
this.minClient = minClient;
|
||||
this.maxClient = maxClient;
|
||||
this.maxTimediff = maxTimediff;
|
||||
this.shortIds = Array.isArray(shortIds) ? shortIds.join(",") : shortIds;
|
||||
this.shortIds = Array.isArray(shortIds) ? shortIds.join(",") : shortIds;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@@ -906,7 +798,9 @@ class RealityStreamSettings extends XrayCommonClass {
|
||||
json.settings.publicKey,
|
||||
json.settings.fingerprint,
|
||||
json.settings.serverName,
|
||||
json.settings.spiderX);}
|
||||
json.settings.spiderX
|
||||
);
|
||||
}
|
||||
return new RealityStreamSettings(
|
||||
json.show,
|
||||
json.xver,
|
||||
@@ -1055,7 +949,6 @@ class StreamSettings extends XrayCommonClass {
|
||||
security = 'none',
|
||||
externalProxy = [],
|
||||
tlsSettings = new TlsStreamSettings(),
|
||||
xtlsSettings = new XtlsStreamSettings(),
|
||||
realitySettings = new RealityStreamSettings(),
|
||||
tcpSettings = new TcpStreamSettings(),
|
||||
kcpSettings = new KcpStreamSettings(),
|
||||
@@ -1071,7 +964,6 @@ class StreamSettings extends XrayCommonClass {
|
||||
this.security = security;
|
||||
this.externalProxy = externalProxy;
|
||||
this.tls = tlsSettings;
|
||||
this.xtls = xtlsSettings;
|
||||
this.reality = realitySettings;
|
||||
this.tcp = tcpSettings;
|
||||
this.kcp = kcpSettings;
|
||||
@@ -1095,18 +987,6 @@ class StreamSettings extends XrayCommonClass {
|
||||
}
|
||||
}
|
||||
|
||||
get isXtls() {
|
||||
return this.security === "xtls";
|
||||
}
|
||||
|
||||
set isXtls(isXtls) {
|
||||
if (isXtls) {
|
||||
this.security = 'xtls';
|
||||
} else {
|
||||
this.security = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
//for Reality
|
||||
get isReality() {
|
||||
return this.security === "reality";
|
||||
@@ -1134,7 +1014,6 @@ class StreamSettings extends XrayCommonClass {
|
||||
json.security,
|
||||
json.externalProxy,
|
||||
TlsStreamSettings.fromJson(json.tlsSettings),
|
||||
XtlsStreamSettings.fromJson(json.xtlsSettings),
|
||||
RealityStreamSettings.fromJson(json.realitySettings),
|
||||
TcpStreamSettings.fromJson(json.tcpSettings),
|
||||
KcpStreamSettings.fromJson(json.kcpSettings),
|
||||
@@ -1154,7 +1033,6 @@ class StreamSettings extends XrayCommonClass {
|
||||
security: this.security,
|
||||
externalProxy: this.externalProxy,
|
||||
tlsSettings: this.isTls ? this.tls.toJson() : undefined,
|
||||
xtlsSettings: this.isXtls ? this.xtls.toJson() : undefined,
|
||||
realitySettings: this.isReality ? this.reality.toJson() : undefined,
|
||||
tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
|
||||
kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
|
||||
@@ -1170,7 +1048,7 @@ class StreamSettings extends XrayCommonClass {
|
||||
|
||||
class Sniffing extends XrayCommonClass {
|
||||
constructor(
|
||||
enabled = true,
|
||||
enabled = false,
|
||||
destOverride = ['http', 'tls', 'quic', 'fakedns'],
|
||||
metadataOnly = false,
|
||||
routeOnly = false) {
|
||||
@@ -1197,6 +1075,27 @@ class Sniffing extends XrayCommonClass {
|
||||
}
|
||||
}
|
||||
|
||||
class Allocate extends XrayCommonClass {
|
||||
constructor(
|
||||
strategy = "always",
|
||||
refresh = 5,
|
||||
concurrency = 3,
|
||||
) {
|
||||
super();
|
||||
this.strategy = strategy;
|
||||
this.refresh = refresh;
|
||||
this.concurrency = concurrency;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
return new Allocate(
|
||||
json.strategy,
|
||||
json.refresh,
|
||||
json.concurrency,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Inbound extends XrayCommonClass {
|
||||
constructor(
|
||||
port = RandomUtil.randomIntRange(10000, 60000),
|
||||
@@ -1206,6 +1105,7 @@ class Inbound extends XrayCommonClass {
|
||||
streamSettings = new StreamSettings(),
|
||||
tag = '',
|
||||
sniffing = new Sniffing(),
|
||||
allocate = new Allocate(),
|
||||
clientStats = '',
|
||||
) {
|
||||
super();
|
||||
@@ -1216,6 +1116,7 @@ class Inbound extends XrayCommonClass {
|
||||
this.stream = streamSettings;
|
||||
this.tag = tag;
|
||||
this.sniffing = sniffing;
|
||||
this.allocate = allocate;
|
||||
this.clientStats = clientStats;
|
||||
}
|
||||
getClientStats() {
|
||||
@@ -1244,18 +1145,6 @@ class Inbound extends XrayCommonClass {
|
||||
}
|
||||
}
|
||||
|
||||
get xtls() {
|
||||
return this.stream.security === 'xtls';
|
||||
}
|
||||
|
||||
set xtls(isXtls) {
|
||||
if (isXtls) {
|
||||
this.stream.security = 'xtls';
|
||||
} else {
|
||||
this.stream.security = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
get network() {
|
||||
return this.stream.network;
|
||||
}
|
||||
@@ -1310,7 +1199,6 @@ class Inbound extends XrayCommonClass {
|
||||
|
||||
get serverName() {
|
||||
if (this.stream.isTls) return this.stream.tls.sni;
|
||||
if (this.stream.isXtls) return this.stream.xtls.sni;
|
||||
if (this.stream.isReality) return this.stream.reality.serverNames;
|
||||
return "";
|
||||
}
|
||||
@@ -1386,12 +1274,7 @@ class Inbound extends XrayCommonClass {
|
||||
|
||||
canEnableReality() {
|
||||
if (![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false;
|
||||
return ["tcp", "http", "grpc"].includes(this.network);
|
||||
}
|
||||
|
||||
canEnableXtls() {
|
||||
if (![Protocols.VLESS, Protocols.TROJAN].includes(this.protocol)) return false;
|
||||
return this.network === "tcp";
|
||||
return ["tcp", "http", "grpc", "splithttp"].includes(this.network);
|
||||
}
|
||||
|
||||
canEnableStream() {
|
||||
@@ -1406,6 +1289,7 @@ class Inbound extends XrayCommonClass {
|
||||
this.stream = new StreamSettings();
|
||||
this.tag = '';
|
||||
this.sniffing = new Sniffing();
|
||||
this.allocate = new Allocate();
|
||||
}
|
||||
|
||||
genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId, security) {
|
||||
@@ -1460,6 +1344,7 @@ class Inbound extends XrayCommonClass {
|
||||
const splithttp = this.stream.splithttp;
|
||||
obj.path = splithttp.path;
|
||||
obj.host = splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host');
|
||||
obj.mode = splithttp.mode;
|
||||
}
|
||||
|
||||
if (security === 'tls') {
|
||||
@@ -1532,6 +1417,7 @@ class Inbound extends XrayCommonClass {
|
||||
const splithttp = this.stream.splithttp;
|
||||
params.set("path", splithttp.path);
|
||||
params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'));
|
||||
params.set("mode", splithttp.mode);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1552,18 +1438,6 @@ class Inbound extends XrayCommonClass {
|
||||
}
|
||||
}
|
||||
|
||||
else if (security === 'xtls') {
|
||||
params.set("security", "xtls");
|
||||
params.set("alpn", this.stream.xtls.alpn);
|
||||
if (this.stream.xtls.settings.allowInsecure) {
|
||||
params.set("allowInsecure", "1");
|
||||
}
|
||||
if (!ObjectUtil.isEmpty(this.stream.xtls.sni)) {
|
||||
params.set("sni", this.stream.xtls.sni);
|
||||
}
|
||||
params.set("flow", flow);
|
||||
}
|
||||
|
||||
else if (security === 'reality') {
|
||||
params.set("security", "reality");
|
||||
params.set("pbk", this.stream.reality.settings.publicKey);
|
||||
@@ -1647,6 +1521,7 @@ class Inbound extends XrayCommonClass {
|
||||
const splithttp = this.stream.splithttp;
|
||||
params.set("path", splithttp.path);
|
||||
params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'));
|
||||
params.set("mode", splithttp.mode);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1729,6 +1604,7 @@ class Inbound extends XrayCommonClass {
|
||||
const splithttp = this.stream.splithttp;
|
||||
params.set("path", splithttp.path);
|
||||
params.set("host", splithttp.host?.length > 0 ? splithttp.host : this.getHeader(splithttp, 'host'));
|
||||
params.set("mode", splithttp.mode);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1761,18 +1637,6 @@ class Inbound extends XrayCommonClass {
|
||||
}
|
||||
}
|
||||
|
||||
else if (security === 'xtls') {
|
||||
params.set("security", "xtls");
|
||||
params.set("alpn", this.stream.xtls.alpn);
|
||||
if (this.stream.xtls.settings.allowInsecure) {
|
||||
params.set("allowInsecure", "1");
|
||||
}
|
||||
if (!ObjectUtil.isEmpty(this.stream.xtls.sni)) {
|
||||
params.set("sni", this.stream.xtls.sni);
|
||||
}
|
||||
params.set("flow", flow);
|
||||
}
|
||||
|
||||
else {
|
||||
params.set("security", "none");
|
||||
}
|
||||
@@ -1885,6 +1749,7 @@ class Inbound extends XrayCommonClass {
|
||||
StreamSettings.fromJson(json.streamSettings),
|
||||
json.tag,
|
||||
Sniffing.fromJson(json.sniffing),
|
||||
Allocate.fromJson(json.allocate),
|
||||
json.clientStats
|
||||
)
|
||||
}
|
||||
@@ -1902,6 +1767,7 @@ class Inbound extends XrayCommonClass {
|
||||
streamSettings: streamSettings,
|
||||
tag: this.tag,
|
||||
sniffing: this.sniffing.toJson(),
|
||||
allocate: this.allocate.toJson(),
|
||||
clientStats: this.clientStats
|
||||
};
|
||||
}
|
||||
@@ -2231,7 +2097,6 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
|
||||
Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
|
||||
constructor(
|
||||
password = RandomUtil.randomSeq(10),
|
||||
flow = '',
|
||||
email = RandomUtil.randomLowerAndNum(8),
|
||||
limitIp = 0,
|
||||
totalGB = 0,
|
||||
@@ -2243,7 +2108,6 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
|
||||
) {
|
||||
super();
|
||||
this.password = password;
|
||||
this.flow = flow;
|
||||
this.email = email;
|
||||
this.limitIp = limitIp;
|
||||
this.totalGB = totalGB;
|
||||
@@ -2257,7 +2121,6 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
|
||||
toJson() {
|
||||
return {
|
||||
password: this.password,
|
||||
flow: this.flow,
|
||||
email: this.email,
|
||||
limitIp: this.limitIp,
|
||||
totalGB: this.totalGB,
|
||||
@@ -2272,7 +2135,6 @@ Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
|
||||
static fromJson(json = {}) {
|
||||
return new Inbound.TrojanSettings.Trojan(
|
||||
json.password,
|
||||
json.flow,
|
||||
json.email,
|
||||
json.limitIp,
|
||||
json.totalGB,
|
||||
@@ -2355,13 +2217,15 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
|
||||
method = SSMethods.BLAKE3_AES_256_GCM,
|
||||
password = RandomUtil.randomShadowsocksPassword(),
|
||||
network = 'tcp,udp',
|
||||
shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()]
|
||||
shadowsockses = [new Inbound.ShadowsocksSettings.Shadowsocks()],
|
||||
ivCheck = false,
|
||||
) {
|
||||
super(protocol);
|
||||
this.method = method;
|
||||
this.password = password;
|
||||
this.network = network;
|
||||
this.shadowsockses = shadowsockses;
|
||||
this.ivCheck = ivCheck;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
@@ -2371,6 +2235,7 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
|
||||
json.password,
|
||||
json.network,
|
||||
json.clients.map(client => Inbound.ShadowsocksSettings.Shadowsocks.fromJson(client)),
|
||||
json.ivCheck,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2379,7 +2244,8 @@ Inbound.ShadowsocksSettings = class extends Inbound.Settings {
|
||||
method: this.method,
|
||||
password: this.password,
|
||||
network: this.network,
|
||||
clients: Inbound.ShadowsocksSettings.toJsonArray(this.shadowsockses)
|
||||
clients: Inbound.ShadowsocksSettings.toJsonArray(this.shadowsockses),
|
||||
ivCheck: this.ivCheck,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -2473,15 +2339,13 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
|
||||
address,
|
||||
port,
|
||||
network = 'tcp,udp',
|
||||
followRedirect = false,
|
||||
timeout = 30
|
||||
followRedirect = false
|
||||
) {
|
||||
super(protocol);
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.network = network;
|
||||
this.followRedirect = followRedirect;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
@@ -2491,7 +2355,6 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
|
||||
json.port,
|
||||
json.network,
|
||||
json.followRedirect,
|
||||
json.timeout,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2501,7 +2364,6 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
|
||||
port: this.port,
|
||||
network: this.network,
|
||||
followRedirect: this.followRedirect,
|
||||
timeout: this.timeout,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -2561,9 +2423,14 @@ Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass {
|
||||
};
|
||||
|
||||
Inbound.HttpSettings = class extends Inbound.Settings {
|
||||
constructor(protocol, accounts = [new Inbound.HttpSettings.HttpAccount()]) {
|
||||
constructor(
|
||||
protocol,
|
||||
accounts = [new Inbound.HttpSettings.HttpAccount()],
|
||||
allowTransparent = false,
|
||||
) {
|
||||
super(protocol);
|
||||
this.accounts = accounts;
|
||||
this.allowTransparent = allowTransparent;
|
||||
}
|
||||
|
||||
addAccount(account) {
|
||||
@@ -2578,12 +2445,14 @@ Inbound.HttpSettings = class extends Inbound.Settings {
|
||||
return new Inbound.HttpSettings(
|
||||
Protocols.HTTP,
|
||||
json.accounts.map(account => Inbound.HttpSettings.HttpAccount.fromJson(account)),
|
||||
json.allowTransparent,
|
||||
);
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
accounts: Inbound.HttpSettings.toJsonArray(this.accounts),
|
||||
allowTransparent: this.allowTransparent,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -2601,13 +2470,19 @@ Inbound.HttpSettings.HttpAccount = class extends XrayCommonClass {
|
||||
};
|
||||
|
||||
Inbound.WireguardSettings = class extends XrayCommonClass {
|
||||
constructor(protocol, mtu = 1420, secretKey = Wireguard.generateKeypair().privateKey, peers = [new Inbound.WireguardSettings.Peer()], kernelMode = false) {
|
||||
constructor(
|
||||
protocol,
|
||||
mtu = 1420,
|
||||
secretKey = Wireguard.generateKeypair().privateKey,
|
||||
peers = [new Inbound.WireguardSettings.Peer()],
|
||||
noKernelTun = false
|
||||
) {
|
||||
super(protocol);
|
||||
this.mtu = mtu;
|
||||
this.secretKey = secretKey;
|
||||
this.pubKey = secretKey.length > 0 ? Wireguard.generateKeypair(secretKey).publicKey : '';
|
||||
this.peers = peers;
|
||||
this.kernelMode = kernelMode;
|
||||
this.noKernelTun = noKernelTun;
|
||||
}
|
||||
|
||||
addPeer() {
|
||||
@@ -2624,7 +2499,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass {
|
||||
json.mtu,
|
||||
json.secretKey,
|
||||
json.peers.map(peer => Inbound.WireguardSettings.Peer.fromJson(peer)),
|
||||
json.kernelMode,
|
||||
json.noKernelTun,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2633,7 +2508,7 @@ Inbound.WireguardSettings = class extends XrayCommonClass {
|
||||
mtu: this.mtu ?? undefined,
|
||||
secretKey: this.secretKey,
|
||||
peers: Inbound.WireguardSettings.Peer.toJsonArray(this.peers),
|
||||
kernelMode: this.kernelMode,
|
||||
noKernelTun: this.noKernelTun,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -77,6 +77,12 @@ const USERS_SECURITY = {
|
||||
ZERO: "zero",
|
||||
};
|
||||
|
||||
const MODE_OPTION = {
|
||||
AUTO: "auto",
|
||||
PACKET_UP: "packet-up",
|
||||
STREAM_UP: "stream-up",
|
||||
};
|
||||
|
||||
Object.freeze(Protocols);
|
||||
Object.freeze(SSMethods);
|
||||
Object.freeze(TLS_FLOW_CONTROL);
|
||||
@@ -85,6 +91,7 @@ Object.freeze(ALPN_OPTION);
|
||||
Object.freeze(OutboundDomainStrategies);
|
||||
Object.freeze(WireguardDomainStrategy);
|
||||
Object.freeze(USERS_SECURITY);
|
||||
Object.freeze(MODE_OPTION);
|
||||
|
||||
|
||||
class CommonClass {
|
||||
@@ -320,16 +327,22 @@ class HttpUpgradeStreamSettings extends CommonClass {
|
||||
}
|
||||
|
||||
class SplitHTTPStreamSettings extends CommonClass {
|
||||
constructor(path = '/', host = '') {
|
||||
constructor(
|
||||
path = '/',
|
||||
host = '',
|
||||
mode = '',
|
||||
) {
|
||||
super();
|
||||
this.path = path;
|
||||
this.host = host;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
return new SplitHTTPStreamSettings(
|
||||
json.path,
|
||||
json.host,
|
||||
json.mode,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -337,6 +350,7 @@ class SplitHTTPStreamSettings extends CommonClass {
|
||||
return {
|
||||
path: this.path,
|
||||
host: this.host,
|
||||
mode: this.mode,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -602,7 +616,7 @@ class Outbound extends CommonClass {
|
||||
|
||||
canEnableReality() {
|
||||
if (![Protocols.VLESS, Protocols.Trojan].includes(this.protocol)) return false;
|
||||
return ["tcp", "http", "grpc"].includes(this.stream.network);
|
||||
return ["tcp", "http", "grpc", "splithttp"].includes(this.stream.network);
|
||||
}
|
||||
|
||||
canEnableStream() {
|
||||
@@ -710,7 +724,7 @@ class Outbound extends CommonClass {
|
||||
} else if (network === 'httpupgrade') {
|
||||
stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host);
|
||||
} else if (network === 'splithttp') {
|
||||
stream.splithttp = new SplitHTTPStreamSettings(json.path, json.host);
|
||||
stream.splithttp = new SplitHTTPStreamSettings(json.path, json.host, json.mode);
|
||||
}
|
||||
|
||||
if (json.tls && json.tls == 'tls') {
|
||||
@@ -754,7 +768,7 @@ class Outbound extends CommonClass {
|
||||
} else if (type === 'httpupgrade') {
|
||||
stream.httpupgrade = new HttpUpgradeStreamSettings(path, host);
|
||||
} else if (type === 'splithttp') {
|
||||
stream.splithttp = new SplitHTTPStreamSettings(path, host);
|
||||
stream.splithttp = new SplitHTTPStreamSettings(path, host, mode);
|
||||
}
|
||||
|
||||
if (security == 'tls') {
|
||||
@@ -851,41 +865,50 @@ Outbound.Settings = class extends CommonClass {
|
||||
Outbound.FreedomSettings = class extends CommonClass {
|
||||
constructor(
|
||||
domainStrategy = '',
|
||||
timeout = '',
|
||||
redirect = '',
|
||||
fragment = {},
|
||||
noise = {}
|
||||
noises = []
|
||||
) {
|
||||
super();
|
||||
this.domainStrategy = domainStrategy;
|
||||
this.timeout = timeout;
|
||||
this.redirect = redirect;
|
||||
this.fragment = fragment;
|
||||
this.noise = noise;
|
||||
this.noises = noises;
|
||||
}
|
||||
|
||||
addNoise() {
|
||||
this.noises.push(new Outbound.FreedomSettings.Noise());
|
||||
}
|
||||
|
||||
delNoise(index) {
|
||||
this.noises.splice(index, 1);
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
return new Outbound.FreedomSettings(
|
||||
json.domainStrategy,
|
||||
json.timeout,
|
||||
json.redirect,
|
||||
json.fragment ? Outbound.FreedomSettings.Fragment.fromJson(json.fragment) : undefined,
|
||||
json.noise ? Outbound.FreedomSettings.Noise.fromJson(json.noise) : undefined,
|
||||
json.noises ? json.noises.map(noise => Outbound.FreedomSettings.Noise.fromJson(noise)) : undefined,
|
||||
);
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
domainStrategy: ObjectUtil.isEmpty(this.domainStrategy) ? undefined : this.domainStrategy,
|
||||
timeout: this.timeout,
|
||||
redirect: this.redirect,
|
||||
redirect: ObjectUtil.isEmpty(this.redirect) ? undefined: this.redirect,
|
||||
fragment: Object.keys(this.fragment).length === 0 ? undefined : this.fragment,
|
||||
noise: Object.keys(this.noise).length === 0 ? undefined : this.noise,
|
||||
noises: this.noises.length === 0 ? undefined : Outbound.FreedomSettings.Noise.toJsonArray(this.noises),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Outbound.FreedomSettings.Fragment = class extends CommonClass {
|
||||
constructor(packets = '1-3', length = '', interval = '') {
|
||||
constructor(
|
||||
packets = '1-3',
|
||||
length = '',
|
||||
interval = ''
|
||||
) {
|
||||
super();
|
||||
this.packets = packets;
|
||||
this.length = length;
|
||||
@@ -900,19 +923,34 @@ Outbound.FreedomSettings.Fragment = class extends CommonClass {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Outbound.FreedomSettings.Noise = class extends CommonClass {
|
||||
constructor(packet = '', delay = '') {
|
||||
constructor(
|
||||
type = 'rand',
|
||||
packet = '10-20',
|
||||
delay = '10-16'
|
||||
) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.packet = packet;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
return new Outbound.FreedomSettings.Noise(
|
||||
json.type,
|
||||
json.packet,
|
||||
json.delay,
|
||||
);
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
type: this.type,
|
||||
packet: this.packet,
|
||||
delay: this.delay,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Outbound.BlackholeSettings = class extends CommonClass {
|
||||
@@ -934,11 +972,19 @@ Outbound.BlackholeSettings = class extends CommonClass {
|
||||
}
|
||||
};
|
||||
Outbound.DNSSettings = class extends CommonClass {
|
||||
constructor(network = 'udp', address = '1.1.1.1', port = 53) {
|
||||
constructor(
|
||||
network = 'udp',
|
||||
address = '',
|
||||
port = 53,
|
||||
nonIPQuery = 'drop',
|
||||
blockTypes = []
|
||||
) {
|
||||
super();
|
||||
this.network = network;
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.nonIPQuery = nonIPQuery;
|
||||
this.blockTypes = blockTypes;
|
||||
}
|
||||
|
||||
static fromJson(json = {}) {
|
||||
@@ -946,6 +992,8 @@ Outbound.DNSSettings = class extends CommonClass {
|
||||
json.network,
|
||||
json.address,
|
||||
json.port,
|
||||
json.nonIPQuery,
|
||||
json.blockTypes,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1144,7 +1192,7 @@ Outbound.WireguardSettings = class extends CommonClass {
|
||||
domainStrategy = '',
|
||||
reserved = '',
|
||||
peers = [new Outbound.WireguardSettings.Peer()],
|
||||
kernelMode = false
|
||||
noKernelTun = false,
|
||||
) {
|
||||
super();
|
||||
this.mtu = mtu;
|
||||
@@ -1155,7 +1203,7 @@ Outbound.WireguardSettings = class extends CommonClass {
|
||||
this.domainStrategy = domainStrategy;
|
||||
this.reserved = Array.isArray(reserved) ? reserved.join(',') : reserved;
|
||||
this.peers = peers;
|
||||
this.kernelMode = kernelMode;
|
||||
this.noKernelTun = noKernelTun;
|
||||
}
|
||||
|
||||
addPeer() {
|
||||
@@ -1175,7 +1223,7 @@ Outbound.WireguardSettings = class extends CommonClass {
|
||||
json.domainStrategy,
|
||||
json.reserved,
|
||||
json.peers.map(peer => Outbound.WireguardSettings.Peer.fromJson(peer)),
|
||||
json.kernelMode,
|
||||
json.noKernelTun,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1188,7 +1236,7 @@ Outbound.WireguardSettings = class extends CommonClass {
|
||||
domainStrategy: WireguardDomainStrategy.includes(this.domainStrategy) ? this.domainStrategy : undefined,
|
||||
reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined,
|
||||
peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers),
|
||||
kernelMode: this.kernelMode,
|
||||
noKernelTun: this.noKernelTun,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ class AllSetting {
|
||||
this.webCertFile = "";
|
||||
this.webKeyFile = "";
|
||||
this.webBasePath = "/";
|
||||
this.sessionMaxAge = 0;
|
||||
this.sessionMaxAge = 60;
|
||||
this.pageSize = 50;
|
||||
this.expireDiff = 0;
|
||||
this.trafficDiff = 0;
|
||||
@@ -16,6 +16,7 @@ class AllSetting {
|
||||
this.tgBotEnable = false;
|
||||
this.tgBotToken = "";
|
||||
this.tgBotProxy = "";
|
||||
this.tgBotAPIServer = "";
|
||||
this.tgBotChatId = "";
|
||||
this.tgRunTime = "@daily";
|
||||
this.tgBotBackup = false;
|
||||
@@ -38,7 +39,7 @@ class AllSetting {
|
||||
this.subURI = "";
|
||||
this.subJsonURI = "";
|
||||
this.subJsonFragment = "";
|
||||
this.subJsonNoise = "";
|
||||
this.subJsonNoises = "";
|
||||
this.subJsonMux = "";
|
||||
this.subJsonRules = "";
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ const ONE_TB = ONE_GB * 1024;
|
||||
const ONE_PB = ONE_TB * 1024;
|
||||
|
||||
function sizeFormat(size) {
|
||||
if (size < 0) {
|
||||
return "0 B";
|
||||
} else if (size < ONE_KB) {
|
||||
if (size <= 0) return "0 B";
|
||||
|
||||
if (size < ONE_KB) {
|
||||
return size.toFixed(0) + " B";
|
||||
} else if (size < ONE_MB) {
|
||||
return (size / ONE_KB).toFixed(2) + " KB";
|
||||
@@ -59,7 +59,7 @@ function formatSecond(second) {
|
||||
return (second / 3600).toFixed(0) + 'h';
|
||||
} else {
|
||||
day = Math.floor(second / 3600 / 24);
|
||||
remain = ((second/3600) - (day*24)).toFixed(0);
|
||||
remain = ((second / 3600) - (day * 24)).toFixed(0);
|
||||
return day + 'd' + (remain > 0 ? ' ' + remain + 'h' : '');
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ function userExpiryColor(threshold, client, isDark = false) {
|
||||
return isDark ? '#2c3950' : '#bcbcbc';
|
||||
}
|
||||
now = new Date().getTime(),
|
||||
expiry = client.expiryTime;
|
||||
expiry = client.expiryTime;
|
||||
switch (true) {
|
||||
case expiry === null:
|
||||
return "#7a316f"; // purple
|
||||
|
||||
@@ -83,10 +83,6 @@ func (a *IndexController) login(c *gin.Context) {
|
||||
logger.Warning("Unable to get session's max age from DB")
|
||||
}
|
||||
|
||||
if sessionMaxAge <= 0 {
|
||||
sessionMaxAge = 60
|
||||
}
|
||||
|
||||
err = session.SetMaxAge(c, sessionMaxAge*60)
|
||||
if err != nil {
|
||||
logger.Warning("Unable to set session's max age")
|
||||
|
||||
@@ -42,12 +42,12 @@ func jsonMsgObj(c *gin.Context, msg string, obj interface{}, err error) {
|
||||
if err == nil {
|
||||
m.Success = true
|
||||
if msg != "" {
|
||||
m.Msg = msg + I18nWeb(c, "success")
|
||||
m.Msg = msg + " " + I18nWeb(c, "success")
|
||||
}
|
||||
} else {
|
||||
m.Success = false
|
||||
m.Msg = msg + I18nWeb(c, "fail") + ": " + err.Error()
|
||||
logger.Warning(msg+I18nWeb(c, "fail")+": ", err)
|
||||
m.Msg = msg + " " + I18nWeb(c, "fail") + ": " + err.Error()
|
||||
logger.Warning(msg+" "+I18nWeb(c, "fail")+": ", err)
|
||||
}
|
||||
c.JSON(http.StatusOK, m)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ type AllSetting struct {
|
||||
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"`
|
||||
TgBotToken string `json:"tgBotToken" form:"tgBotToken"`
|
||||
TgBotProxy string `json:"tgBotProxy" form:"tgBotProxy"`
|
||||
TgBotAPIServer string `json:"tgBotAPIServer" form:"tgBotAPIServer"`
|
||||
TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"`
|
||||
TgRunTime string `json:"tgRunTime" form:"tgRunTime"`
|
||||
TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"`
|
||||
@@ -52,7 +53,7 @@ type AllSetting struct {
|
||||
SubJsonPath string `json:"subJsonPath" form:"subJsonPath"`
|
||||
SubJsonURI string `json:"subJsonURI" form:"subJsonURI"`
|
||||
SubJsonFragment string `json:"subJsonFragment" form:"subJsonFragment"`
|
||||
SubJsonNoise string `json:"subJsonNoise" form:"subJsonNoise"`
|
||||
SubJsonNoises string `json:"subJsonNoises" form:"subJsonNoises"`
|
||||
SubJsonMux string `json:"subJsonMux" form:"subJsonMux"`
|
||||
SubJsonRules string `json:"subJsonRules" form:"subJsonRules"`
|
||||
Datepicker string `json:"datepicker" form:"datepicker"`
|
||||
|
||||
@@ -449,7 +449,7 @@
|
||||
<a-row justify="center" class="centered">
|
||||
<a-col :span="24">
|
||||
<a-select ref="selectLang" v-model="lang"
|
||||
@change="setLang(lang)" style="width: 150px;"
|
||||
@change="setLang(lang)" style="width: 200px;"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="l.value" label="English" v-for="l in supportLangs">
|
||||
<span role="img" aria-label="l.name" v-text="l.icon"></span>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<a-form-item label='{{ i18n "pages.client.clientCount" }}' v-if="clientsBulkModal.emailMethod < 2">
|
||||
<a-input-number v-model="clientsBulkModal.quantity" :min="1" :max="100"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.protocol === Protocols.VMESS" label='Security'>
|
||||
<a-form-item label='{{ i18n "security" }}' v-if="inbound.protocol === Protocols.VMESS">
|
||||
<a-select v-model="clientsBulkModal.security" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
@@ -39,12 +39,6 @@
|
||||
<a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Flow' v-if="clientsBulkModal.inbound.xtls">
|
||||
<a-select v-model="clientsBulkModal.flow" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
|
||||
<a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="app.subSettings.enable">
|
||||
<template slot="label">
|
||||
<a-tooltip>
|
||||
@@ -181,9 +175,6 @@
|
||||
if (clientsBulkModal.inbound.canEnableTlsFlow()) {
|
||||
newClient.flow = clientsBulkModal.flow;
|
||||
}
|
||||
if (clientsBulkModal.inbound.xtls) {
|
||||
newClient.flow = clientsBulkModal.flow;
|
||||
}
|
||||
newClient.reset = clientsBulkModal.reset;
|
||||
clients.push(newClient);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{{define "dnsModal"}}
|
||||
<a-modal id="dns-modal" v-model="dnsModal.visible" :title="dnsModal.title" @ok="dnsModal.ok" :closable="true" :mask-closable="false" :ok-text="dnsModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
|
||||
<a-modal id="dns-modal" v-model="dnsModal.visible" :title="dnsModal.title" @ok="dnsModal.ok" :closable="true"
|
||||
:mask-closable="false" :ok-text="dnsModal.okText" cancel-text='{{ i18n "close" }}'
|
||||
:class="themeSwitcher.currentTheme">
|
||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label='{{ i18n "pages.xray.outbound.address" }}'>
|
||||
<a-input v-model.trim="dnsModal.dnsServer.address"></a-input>
|
||||
@@ -8,18 +10,29 @@
|
||||
<a-button icon="plus" size="small" type="primary" @click="dnsModal.dnsServer.domains.push('')"></a-button>
|
||||
<template v-for="(domain, index) in dnsModal.dnsServer.domains">
|
||||
<a-input v-model.trim="dnsModal.dnsServer.domains[index]">
|
||||
<a-button icon="minus" size="small" slot="addonAfter" @click="dnsModal.dnsServer.domains.splice(index,1)"></a-button>
|
||||
<a-button icon="minus" size="small" slot="addonAfter"
|
||||
@click="dnsModal.dnsServer.domains.splice(index,1)"></a-button>
|
||||
</a-input>
|
||||
</template>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.xray.dns.strategy" }}' v-if="isAdvanced">
|
||||
<a-select v-model="dnsModal.dnsServer.queryStrategy" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select v-model="dnsModal.dnsServer.queryStrategy" style="width: 100%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']"> [[ l ]] </a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Skip Fallback' v-if="isAdvanced">
|
||||
<a-switch v-model="dnsModal.dnsServer.skipFallback"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.xray.dns.expectIPs"}}'>
|
||||
<a-button icon="plus" size="small" type="primary" @click="dnsModal.dnsServer.expectIPs.push('')"></a-button>
|
||||
<template v-for="(domain, index) in dnsModal.dnsServer.expectIPs">
|
||||
<a-input v-model.trim="dnsModal.dnsServer.expectIPs[index]">
|
||||
<a-button icon="minus" size="small" slot="addonAfter"
|
||||
@click="dnsModal.dnsServer.expectIPs.splice(index,1)"></a-button>
|
||||
</a-input>
|
||||
</template>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
<script>
|
||||
@@ -32,20 +45,24 @@
|
||||
dnsServer: {
|
||||
address: "localhost",
|
||||
domains: [],
|
||||
expectIPs: [],
|
||||
queryStrategy: 'UseIP',
|
||||
skipFallback: true,
|
||||
},
|
||||
ok() {
|
||||
domains = dnsModal.dnsServer.domains.filter(d => d.length > 0);
|
||||
expectIPs = dnsModal.dnsServer.expectIPs.filter(ip => ip.length > 0);
|
||||
dnsModal.dnsServer.domains = domains;
|
||||
newDnsServer = domains.length > 0 ? dnsModal.dnsServer : dnsModal.dnsServer.address;
|
||||
dnsModal.dnsServer.expectIPs = expectIPs;
|
||||
newDnsServer = (domains.length > 0 || expectIPs.length > 0) ? dnsModal.dnsServer : dnsModal.dnsServer.address;
|
||||
ObjectUtil.execute(dnsModal.confirm, newDnsServer);
|
||||
},
|
||||
|
||||
show({
|
||||
title = '',
|
||||
okText = '{{ i18n "confirm" }}',
|
||||
dnsServer,
|
||||
confirm = (dnsServer) => {},
|
||||
confirm = (dnsServer) => { },
|
||||
isEdit = false
|
||||
}) {
|
||||
this.title = title;
|
||||
@@ -59,6 +76,7 @@
|
||||
this.dnsServer = {
|
||||
address: dnsServer ?? "",
|
||||
domains: [],
|
||||
expectIPs: [],
|
||||
queryStrategy: 'UseIP',
|
||||
skipFallback: true,
|
||||
}
|
||||
@@ -67,6 +85,7 @@
|
||||
this.dnsServer = {
|
||||
address: "localhost",
|
||||
domains: [],
|
||||
expectIPs: [],
|
||||
queryStrategy: 'UseIP',
|
||||
skipFallback: true,
|
||||
}
|
||||
@@ -85,8 +104,8 @@
|
||||
},
|
||||
computed: {
|
||||
isAdvanced: {
|
||||
get: function() {
|
||||
return dnsModal.dnsServer.domains.length > 0
|
||||
get: function () {
|
||||
return dnsModal.dnsServer.domains.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
15
web/html/xui/form/allocate.html
Normal file
15
web/html/xui/form/allocate.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{{define "form/allocate"}}
|
||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label='Strategy'>
|
||||
<a-select v-model="inbound.allocate.strategy" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="s in ['always','random']" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Refresh'>
|
||||
<a-input-number v-model.number="inbound.allocate.refresh" min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label='Concurrency'>
|
||||
<a-input-number v-model.number="inbound.allocate.concurrency" min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
@@ -39,7 +39,7 @@
|
||||
</template>
|
||||
<a-input v-model.trim="client.id"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.protocol === Protocols.VMESS" label='Security'>
|
||||
<a-form-item v-if="inbound.protocol === Protocols.VMESS" label='{{ i18n "security" }}'>
|
||||
<a-select v-model="client.security" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
@@ -104,12 +104,6 @@
|
||||
</a-textarea>
|
||||
</a-form>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.xtls" label='Flow'>
|
||||
<a-select v-model="client.flow" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
|
||||
<a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="inbound.canEnableTlsFlow()" label='Flow'>
|
||||
<a-select v-model="client.flow" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
|
||||
|
||||
@@ -115,7 +115,19 @@
|
||||
</template>
|
||||
|
||||
<!-- sniffing -->
|
||||
<template>
|
||||
{{template "form/sniffing"}}
|
||||
</template>
|
||||
<a-collapse>
|
||||
<a-collapse-panel header='Sniffing'>
|
||||
{{template "form/sniffing"}}
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
|
||||
<!-- allocate -->
|
||||
<!-- Temporarily disabled until we accepts range for port allocation
|
||||
<a-collapse>
|
||||
<a-collapse-panel header='Allocate'>
|
||||
{{template "form/allocate"}}
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
-->
|
||||
|
||||
{{end}}
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
<a-select-option v-for="s in OutboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Timeout'>
|
||||
<a-input-number v-model.number="outbound.settings.timeout" min="0" ></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label='Redirect'>
|
||||
<a-input v-model="outbound.settings.redirect"></a-input>
|
||||
</a-form-item>
|
||||
@@ -46,16 +43,39 @@
|
||||
<a-input v-model.trim="outbound.settings.fragment.interval"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<a-form-item label='Noise'>
|
||||
<a-switch :checked="Object.keys(outbound.settings.noise).length >0" @change="checked => outbound.settings.noise = checked ? new Outbound.FreedomSettings.Noise() : {}"></a-switch>
|
||||
|
||||
<!-- Switch for Noises -->
|
||||
<a-form-item label='Noises'>
|
||||
<a-switch :checked="outbound.settings.noises.length > 0"
|
||||
@change="checked => outbound.settings.noises = checked ? [new Outbound.FreedomSettings.Noise()] : []">
|
||||
</a-switch>
|
||||
</a-form-item>
|
||||
<template v-if="Object.keys(outbound.settings.noise).length >0">
|
||||
<a-form-item label='Packet'>
|
||||
<a-input v-model.trim="outbound.settings.noise.packet"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='Delay'>
|
||||
<a-input v-model.trim="outbound.settings.noise.delay"></a-input>
|
||||
|
||||
<!-- Add Noise Button -->
|
||||
<template v-if="outbound.settings.noises.length > 0">
|
||||
<a-form-item label="Noises">
|
||||
<a-button icon="plus" type="primary" size="small" @click="outbound.settings.addNoise()"></a-button>
|
||||
</a-form-item>
|
||||
|
||||
<!-- Noise Configurations -->
|
||||
<a-form v-for="(noise, index) in outbound.settings.noises" :key="index" :colon="false" :label-col="{ md: {span:8} }"
|
||||
:wrapper-col="{ md: {span:14} }">
|
||||
<a-divider style="margin:0;"> Noise [[ index + 1 ]]
|
||||
<a-icon v-if="outbound.settings.noises.length > 1" type="delete" @click="() => outbound.settings.delNoise(index)"
|
||||
style="color: rgb(255, 77, 79); cursor: pointer;"></a-icon>
|
||||
</a-divider>
|
||||
<a-form-item label='Type'>
|
||||
<a-select v-model="noise.type" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="s in ['rand','base64','str']" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Packet'>
|
||||
<a-input v-model.trim="noise.packet"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='Delay'>
|
||||
<a-input v-model.trim="noise.delay"></a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -75,6 +95,14 @@
|
||||
<a-select-option v-for="s in ['udp','tcp']" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='non-IP queries'>
|
||||
<a-select v-model="outbound.settings.nonIPQuery" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="s in ['drop','skip']" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="outbound.settings.nonIPQuery === 'skip'" label='Block Types' >
|
||||
<a-input v-model.number="outbound.settings.blockTypes"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<!-- wireguard settings -->
|
||||
@@ -119,8 +147,8 @@
|
||||
<a-form-item label='Workers'>
|
||||
<a-input-number v-model.number="outbound.settings.workers" min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label='Kernel Mode'>
|
||||
<a-switch v-model="outbound.settings.kernelMode"></a-switch>
|
||||
<a-form-item label='No Kernel Tun'>
|
||||
<a-switch v-model="outbound.settings.noKernelTun"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<template slot="label">
|
||||
@@ -179,11 +207,15 @@
|
||||
<a-form-item label='ID'>
|
||||
<a-input v-model.trim="outbound.settings.id"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='Security'>
|
||||
<a-select v-model="outbound.settings.security" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<!-- vmess settings -->
|
||||
<template v-if="outbound.protocol === Protocols.VMess">
|
||||
<a-form-item label='Security'>
|
||||
<a-select v-model="outbound.settings.security" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<!-- vless settings -->
|
||||
<template v-if="outbound.canEnableTlsFlow()">
|
||||
@@ -235,13 +267,13 @@
|
||||
<template v-if="outbound.canEnableStream()">
|
||||
<a-form-item label='{{ i18n "transmission" }}'>
|
||||
<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="tcp">TCP (RAW)</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">H2</a-select-option>
|
||||
<a-select-option value="http">HTTP</a-select-option>
|
||||
<a-select-option value="grpc">gRPC</a-select-option>
|
||||
<a-select-option value="httpupgrade">HTTPUpgrade</a-select-option>
|
||||
<a-select-option value="splithttp">SplitHTTP</a-select-option>
|
||||
<a-select-option value="splithttp">SplitHTTP (XHTTP)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<template v-if="outbound.stream.network === 'tcp'">
|
||||
@@ -348,6 +380,11 @@
|
||||
<a-form-item label='{{ i18n "path" }}'>
|
||||
<a-input v-model.trim="outbound.stream.splithttp.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='Mode'>
|
||||
<a-select v-model="outbound.stream.splithttp.mode" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -420,8 +457,8 @@
|
||||
</a-form-item>
|
||||
<a-form-item label="Multipath TCP">
|
||||
<a-switch v-model.trim="outbound.stream.sockopt.tcpMptcp"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label="TCP No-Delay">
|
||||
</a-form-item>
|
||||
<a-form-item label="TCP No-Delay" v-if="outbound.stream.sockopt.tcpMptcp">
|
||||
<a-switch v-model="outbound.stream.sockopt.tcpNoDelay"></a-switch>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
@@ -16,8 +16,5 @@
|
||||
<a-form-item label='Follow Redirect'>
|
||||
<a-switch v-model="inbound.settings.followRedirect"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='Timeout'>
|
||||
<a-input-number v-model.number="inbound.settings.timeout" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
|
||||
@@ -19,5 +19,8 @@
|
||||
</template>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
<a-form-item label="Allow Transparent">
|
||||
<a-switch v-model="inbound.settings.allowTransparent" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
|
||||
@@ -43,5 +43,8 @@
|
||||
<a-select-option value="udp">UDP</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='ivCheck'>
|
||||
<a-switch v-model="inbound.settings.ivCheck"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<tr class="client-table-header">
|
||||
<th>{{ i18n "pages.inbounds.email" }}</th>
|
||||
<th>ID</th>
|
||||
<th>Security</th>
|
||||
<th>{{ i18n "security" }}</th>
|
||||
</tr>
|
||||
<tr v-for="(client, index) in inbound.settings.vmesses" :class="index % 2 == 1 ? 'client-table-odd-row' : ''">
|
||||
<td>[[ client.email ]]</td>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<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 label='No Kernel Tun'>
|
||||
<a-switch v-model="inbound.settings.noKernelTun"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label="Peers">
|
||||
<a-button icon="plus" type="primary" size="small" @click="inbound.settings.addPeer()"></a-button>
|
||||
|
||||
56
web/html/xui/form/reality_settings.html
Normal file
56
web/html/xui/form/reality_settings.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{{define "form/realitySettings"}}
|
||||
<template>
|
||||
<a-form-item label='Show'>
|
||||
<a-switch v-model="inbound.stream.reality.show"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='Xver'>
|
||||
<a-input-number v-model.number="inbound.stream.reality.xver" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label='uTLS'>
|
||||
<a-select v-model="inbound.stream.reality.settings.fingerprint" style="width: 50%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Dest (Target)'>
|
||||
<a-input v-model.trim="inbound.stream.reality.dest"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='SNI'>
|
||||
<a-input v-model.trim="inbound.stream.reality.serverNames"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='Max Time Diff (ms)'>
|
||||
<a-input-number v-model.number="inbound.stream.reality.maxTimediff" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<!-- we also have this but i think it's not necessary
|
||||
<a-form-item label='Min Client'>
|
||||
<a-input v-model.trim="inbound.stream.reality.minClient"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='Max Client'>
|
||||
<a-input v-model.trim="inbound.stream.reality.maxClient"></a-input>
|
||||
</a-form-item>
|
||||
-->
|
||||
<a-form-item>
|
||||
<template slot="label">
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "reset" }}</span>
|
||||
</template> Short IDs <a-icon @click="inbound.stream.reality.shortIds = RandomUtil.randomShortIds()"
|
||||
type="sync"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input v-model.trim="inbound.stream.reality.shortIds"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='SpiderX'>
|
||||
<a-input v-model.trim="inbound.stream.reality.settings.spiderX"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.privatekey" }}'>
|
||||
<a-input v-model.trim="inbound.stream.reality.privateKey"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.publicKey" }}'>
|
||||
<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-form-item>
|
||||
</template>
|
||||
{{end}}
|
||||
@@ -1,9 +1,8 @@
|
||||
{{define "form/sniffing"}}
|
||||
<a-divider style="margin:5px 0 0;"></a-divider>
|
||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
Sniffing
|
||||
{{ i18n "enabled" }}
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "pages.inbounds.noRecommendKeepDefault" }}</span>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
<a-form-item label='{{ i18n "transmission" }}'>
|
||||
<a-select v-model="inbound.stream.network" style="width: 75%" @change="streamNetworkChange"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value="tcp">TCP</a-select-option>
|
||||
<a-select-option value="tcp">TCP (RAW)</a-select-option>
|
||||
<a-select-option value="kcp">mKCP</a-select-option>
|
||||
<a-select-option value="ws">WebSocket</a-select-option>
|
||||
<a-select-option value="http">H2</a-select-option>
|
||||
<a-select-option value="http">HTTP</a-select-option>
|
||||
<a-select-option value="grpc">gRPC</a-select-option>
|
||||
<a-select-option value="httpupgrade">HTTPUpgrade</a-select-option>
|
||||
<a-select-option value="splithttp">SplitHTTP</a-select-option>
|
||||
<a-select-option value="splithttp">SplitHTTP (XHTTP)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<a-form-item label="Multipath TCP">
|
||||
<a-switch v-model.trim="inbound.stream.sockopt.tcpMptcp"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label="TCP No-Delay">
|
||||
<a-form-item label="TCP No-Delay" v-if="inbound.stream.sockopt.tcpMptcp">
|
||||
<a-switch v-model.trim="inbound.stream.sockopt.tcpNoDelay"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label="V6 Only">
|
||||
|
||||
@@ -4,21 +4,30 @@
|
||||
<a-input v-model.trim="inbound.stream.splithttp.host"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "path" }}'>
|
||||
<a-input v-model.trim="inbound.stream.splithttp.path"></a-input>
|
||||
<a-input v-model.trim="inbound.stream.splithttp.path"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestHeader" }}'>
|
||||
<a-button icon="plus" size="small" @click="inbound.stream.splithttp.addHeader('host', '')"></a-button>
|
||||
<a-button icon="plus" size="small" @click="inbound.stream.splithttp.addHeader('host', '')"></a-button>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{span:24}">
|
||||
<a-input-group compact v-for="(header, index) in inbound.stream.splithttp.headers">
|
||||
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
|
||||
<a-input style="width: 50%" v-model.trim="header.name"
|
||||
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
|
||||
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
|
||||
</a-input>
|
||||
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
|
||||
<a-button slot="addonAfter" size="small" @click="inbound.stream.splithttp.removeHeader(index)">-</a-button>
|
||||
<a-input style="width: 50%" v-model.trim="header.value"
|
||||
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
|
||||
<a-button slot="addonAfter" size="small"
|
||||
@click="inbound.stream.splithttp.removeHeader(index)">-</a-button>
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
<a-form-item label='Mode'>
|
||||
<a-select v-model="inbound.stream.splithttp.mode" style="width: 50%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Concurrent Upload">
|
||||
<a-input v-model.trim="inbound.stream.splithttp.scMaxConcurrentPosts"></a-input>
|
||||
</a-form-item>
|
||||
@@ -34,5 +43,20 @@
|
||||
<a-form-item label="No SSE Header">
|
||||
<a-switch v-model="inbound.stream.splithttp.noSSEHeader"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Concurrency" v-if="!inbound.stream.splithttp.xmux.maxConnections">
|
||||
<a-input v-model="inbound.stream.splithttp.xmux.maxConcurrency"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Connections" v-if="!inbound.stream.splithttp.xmux.maxConcurrency">
|
||||
<a-input v-model="inbound.stream.splithttp.xmux.maxConnections"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Reuse Times">
|
||||
<a-input v-model="inbound.stream.splithttp.xmux.cMaxReuseTimes"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="Max Lifetime (ms)">
|
||||
<a-input v-model="inbound.stream.splithttp.xmux.cMaxLifetimeMs"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="No gRPC Header">
|
||||
<a-switch v-model="inbound.stream.splithttp.noGRPCHeader"></a-switch>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -5,18 +5,7 @@
|
||||
<a-form-item label='{{ i18n "security" }}'>
|
||||
<a-radio-group v-model="inbound.stream.security" button-style="solid">
|
||||
<a-radio-button value="none">{{ i18n "none" }}</a-radio-button>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "pages.inbounds.xtlsDesc" }}</span>
|
||||
</template>
|
||||
<a-radio-button v-if="inbound.canEnableXtls()" value="xtls">XTLS</a-radio-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "pages.inbounds.realityDesc" }}</span>
|
||||
</template>
|
||||
<a-radio-button v-if="inbound.canEnableReality()" value="reality">REALITY</a-radio-button>
|
||||
</a-tooltip>
|
||||
<a-radio-button v-if="inbound.canEnableReality()" value="reality">Reality</a-radio-button>
|
||||
<a-radio-button value="tls">TLS</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
@@ -34,16 +23,19 @@
|
||||
</a-form-item>
|
||||
<a-form-item label="Min/Max Version">
|
||||
<a-input-group compact>
|
||||
<a-select v-model="inbound.stream.tls.minVersion" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select v-model="inbound.stream.tls.minVersion" style="width: 50%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model="inbound.stream.tls.maxVersion" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select v-model="inbound.stream.tls.maxVersion" style="width: 50%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="uTLS">
|
||||
<a-select v-model="inbound.stream.tls.settings.fingerprint" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select v-model="inbound.stream.tls.settings.fingerprint" style="width: 50%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option value=''>None</a-select-option>
|
||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
@@ -71,8 +63,10 @@
|
||||
<a-radio-button :value="true">{{ i18n "pages.inbounds.certificatePath" }}</a-radio-button>
|
||||
<a-radio-button :value="false">{{ i18n "pages.inbounds.certificateContent" }}</a-radio-button>
|
||||
</a-radio-group>
|
||||
<a-button icon="plus" v-if="index === 0" type="primary" size="small" @click="inbound.stream.tls.addCert()" style="margin-left: 10px"></a-button>
|
||||
<a-button icon="minus" v-if="inbound.stream.tls.certs.length>1" type="primary" size="small" @click="inbound.stream.tls.removeCert(index)" style="margin-left: 10px"></a-button>
|
||||
<a-button icon="plus" v-if="index === 0" type="primary" size="small" @click="inbound.stream.tls.addCert()"
|
||||
style="margin-left: 10px"></a-button>
|
||||
<a-button icon="minus" v-if="inbound.stream.tls.certs.length>1" type="primary" size="small"
|
||||
@click="inbound.stream.tls.removeCert(index)" style="margin-left: 10px"></a-button>
|
||||
</a-form-item>
|
||||
<template v-if="cert.useFile">
|
||||
<a-form-item label='{{ i18n "pages.inbounds.publicKey" }}'>
|
||||
@@ -82,7 +76,8 @@
|
||||
<a-input v-model.trim="cert.keyFile"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label=" ">
|
||||
<a-button type="primary" icon="import" @click="setDefaultCertData(index)">{{ i18n "pages.inbounds.setDefaultCert" }}</a-button>
|
||||
<a-button type="primary" icon="import" @click="setDefaultCertData(index)">
|
||||
{{ i18n "pages.inbounds.setDefaultCert" }}</a-button>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -104,108 +99,15 @@
|
||||
<a-select-option v-for="key in USAGE_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="Build Chain">
|
||||
<a-form-item label="Build Chain" v-if="cert.usage === 'issue'">
|
||||
<a-switch v-model="cert.buildChain"></a-switch>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- xtls settings -->
|
||||
<template v-else-if="inbound.xtls">
|
||||
<a-form-item label="SNI" placeholder="Server Name Indication">
|
||||
<a-input v-model.trim="inbound.stream.xtls.sni"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="ALPN">
|
||||
<a-select mode="multiple" :dropdown-class-name="themeSwitcher.currentTheme" v-model="inbound.stream.xtls.alpn">
|
||||
<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-switch v-model="inbound.stream.xtls.settings.allowInsecure"></a-switch>
|
||||
</a-form-item>
|
||||
<template v-for="cert,index in inbound.stream.xtls.certs">
|
||||
<a-form-item label='{{ i18n "certificate" }}'>
|
||||
<a-radio-group v-model="cert.useFile" button-style="solid">
|
||||
<a-radio-button :value="true">{{ i18n "pages.inbounds.certificatePath" }}</a-radio-button>
|
||||
<a-radio-button :value="false">{{ i18n "pages.inbounds.certificateContent" }}</a-radio-button>
|
||||
</a-radio-group>
|
||||
<a-button icon="plus" v-if="index === 0" type="primary" size="small" @click="inbound.stream.xtls.addCert()" style="margin-left: 10px"></a-button>
|
||||
<a-button icon="minus" v-if="inbound.stream.xtls.certs.length>1" type="primary" size="small" @click="inbound.stream.xtls.removeCert(index)" style="margin-left: 10px"></a-button>
|
||||
</a-form-item>
|
||||
<template v-if="cert.useFile">
|
||||
<a-form-item label='{{ i18n "pages.inbounds.publicKey" }}'>
|
||||
<a-input v-model.trim="cert.certFile"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.privatekey" }}'>
|
||||
<a-input v-model.trim="cert.keyFile"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label=" ">
|
||||
<a-button type="primary" icon="import" @click="setDefaultCertXtls(index)">{{ i18n "pages.inbounds.setDefaultCert" }}</a-button>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.publicKey" }}'>
|
||||
<a-input type="textarea" :rows="3" v-model="cert.cert"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.privatekey" }}'>
|
||||
<a-input type="textarea" :rows="3" v-model="cert.key"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<a-form-item label='OCSP stapling'>
|
||||
<a-input-number v-model.number="cert.ocspStapling" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label="One Time Loading">
|
||||
<a-switch v-model="cert.oneTimeLoading"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='Usage Option'>
|
||||
<a-select v-model="cert.usage" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in USAGE_OPTION" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- reality settings -->
|
||||
<template v-if="inbound.stream.isReality">
|
||||
<a-form-item label='Show'>
|
||||
<a-switch v-model="inbound.stream.reality.show"></a-switch>
|
||||
</a-form-item>
|
||||
<a-form-item label='Xver'>
|
||||
<a-input-number v-model.number="inbound.stream.reality.xver" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label='uTLS'>
|
||||
<a-select v-model="inbound.stream.reality.settings.fingerprint" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label='Dest'>
|
||||
<a-input v-model.trim="inbound.stream.reality.dest"></a-input>
|
||||
</a-form-item>
|
||||
<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 "reset" }}</span>
|
||||
</template> Short IDs <a-icon @click="inbound.stream.reality.shortIds = RandomUtil.randomShortIds()" type="sync"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input v-model.trim="inbound.stream.reality.shortIds"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='SpiderX'>
|
||||
<a-input v-model.trim="inbound.stream.reality.settings.spiderX"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.privatekey" }}'>
|
||||
<a-input v-model.trim="inbound.stream.reality.privateKey"></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.publicKey" }}'>
|
||||
<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-form-item>
|
||||
{{template "form/realitySettings"}}
|
||||
</template>
|
||||
</a-form>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -58,6 +58,14 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template v-if="inbound.isSplithttp">
|
||||
<tr>
|
||||
<td>Mode</td>
|
||||
<td>
|
||||
<a-tag>[[ inbound.stream.splithttp.mode ]]</a-tag>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<template v-if="inbound.isKcp">
|
||||
<tr>
|
||||
<td>kcp {{ i18n "encryption" }}</td>
|
||||
@@ -139,16 +147,13 @@
|
||||
<a-tag>[[ infoModal.clientSettings.id ]]</a-tag>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="infoModal.inbound.canEnableTlsFlow()">
|
||||
<td>Flow</td>
|
||||
<td v-if="infoModal.clientSettings.flow">
|
||||
<a-tag>[[ infoModal.clientSettings.flow ]]</a-tag>
|
||||
</td>
|
||||
<td v-else>
|
||||
<a-tag color="orange">{{ i18n "none" }}</a-tag>
|
||||
<tr v-if="dbInbound.isVMess">
|
||||
<td>{{ i18n "security" }}</td>
|
||||
<td>
|
||||
<a-tag>[[ infoModal.clientSettings.security ]]</a-tag>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="infoModal.inbound.xtls">
|
||||
<tr v-if="infoModal.inbound.canEnableTlsFlow()">
|
||||
<td>Flow</td>
|
||||
<td v-if="infoModal.clientSettings.flow">
|
||||
<a-tag>[[ infoModal.clientSettings.flow ]]</a-tag>
|
||||
@@ -364,8 +369,8 @@
|
||||
<td>[[ inbound.settings.mtu ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Kernel Mode</td>
|
||||
<td>[[ inbound.settings.kernelMode ]]</td>
|
||||
<td>No Kernel Tun</td>
|
||||
<td>[[ inbound.settings.noKernelTun ]]</td>
|
||||
</tr>
|
||||
<template v-for="(peer, index) in inbound.settings.peers">
|
||||
<tr>
|
||||
|
||||
@@ -102,11 +102,6 @@
|
||||
client.flow = "";
|
||||
});
|
||||
}
|
||||
if ((this.inModal.inbound.protocol == Protocols.VLESS || this.inModal.inbound.protocol == Protocols.TROJAN) && !inModal.inbound.xtls) {
|
||||
this.inModal.inbound.settings.vlesses.forEach(client => {
|
||||
client.flow = "";
|
||||
});
|
||||
}
|
||||
},
|
||||
SSMethodChange() {
|
||||
if (this.inModal.inbound.isSSMultiUser) {
|
||||
@@ -132,10 +127,6 @@
|
||||
inModal.inbound.stream.tls.certs[index].certFile = app.defaultCert;
|
||||
inModal.inbound.stream.tls.certs[index].keyFile = app.defaultKey;
|
||||
},
|
||||
setDefaultCertXtls(index) {
|
||||
inModal.inbound.stream.xtls.certs[index].certFile = app.defaultCert;
|
||||
inModal.inbound.stream.xtls.certs[index].keyFile = app.defaultKey;
|
||||
},
|
||||
async getNewX25519Cert() {
|
||||
inModal.loading(true);
|
||||
const msg = await HttpUtil.post('/server/getNewX25519Cert');
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper {
|
||||
margin:-10px 22px -10px !important;
|
||||
margin:-10px 22px !important;
|
||||
}
|
||||
.ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper .ant-table {
|
||||
border-bottom-left-radius: 1rem;
|
||||
@@ -40,7 +40,7 @@
|
||||
padding: .5rem;
|
||||
}
|
||||
.ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper {
|
||||
margin:-10px 2px -10px !important;
|
||||
margin:-10px 2px !important;
|
||||
}
|
||||
}
|
||||
.ant-col-sm-24 {
|
||||
@@ -338,7 +338,6 @@
|
||||
<template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS">
|
||||
<a-tag style="margin:0;" color="green">[[ dbInbound.toInbound().stream.network ]]</a-tag>
|
||||
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isTls" color="blue">TLS</a-tag>
|
||||
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isXtls" color="blue">XTLS</a-tag>
|
||||
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isReality" color="blue">Reality</a-tag>
|
||||
</template>
|
||||
</template>
|
||||
@@ -549,7 +548,7 @@
|
||||
<script src="{{ .base_path }}assets/qrcode/qrious2.min.js?{{ .cur_ver }}"></script>
|
||||
<script src="{{ .base_path }}assets/clipboard/clipboard.min.js?{{ .cur_ver }}"></script>
|
||||
<script src="{{ .base_path }}assets/uri/URI.min.js?{{ .cur_ver }}"></script>
|
||||
<script src="{{ .base_path }}assets/js/model/xray.js?{{ .cur_ver }}"></script>
|
||||
<script src="{{ .base_path }}assets/js/model/inbound.js?{{ .cur_ver }}"></script>
|
||||
<script src="{{ .base_path }}assets/js/model/dbinbound.js?{{ .cur_ver }}"></script>
|
||||
{{template "component/themeSwitcher" .}}
|
||||
{{template "component/persianDatepicker" .}}
|
||||
@@ -733,7 +732,7 @@
|
||||
this.inbounds.push(to_inbound);
|
||||
this.dbInbounds.push(dbInbound);
|
||||
if ([Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(inbound.protocol)) {
|
||||
if (inbound.protocol === Protocols.SHADOWSOCKS && (!to_inbound.isSSMultiUser)) {
|
||||
if (dbInbound.isSS && (!to_inbound.isSSMultiUser)) {
|
||||
continue;
|
||||
}
|
||||
this.clientCount[inbound.id] = this.getClientCounts(inbound, to_inbound);
|
||||
@@ -935,6 +934,7 @@
|
||||
settings: Inbound.Settings.getSettings(baseInbound.protocol).toString(),
|
||||
streamSettings: baseInbound.stream.toString(),
|
||||
sniffing: baseInbound.sniffing.toString(),
|
||||
allocate: baseInbound.allocate.toString(),
|
||||
};
|
||||
await this.submit('/panel/inbound/add', data, inModal);
|
||||
},
|
||||
@@ -980,6 +980,7 @@
|
||||
};
|
||||
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
|
||||
data.sniffing = inbound.sniffing.toString();
|
||||
data.allocate = inbound.allocate.toString();
|
||||
|
||||
await this.submit('/panel/inbound/add', data, inModal);
|
||||
},
|
||||
@@ -999,6 +1000,7 @@
|
||||
};
|
||||
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
|
||||
data.sniffing = inbound.sniffing.toString();
|
||||
data.allocate = inbound.allocate.toString();
|
||||
|
||||
await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
|
||||
},
|
||||
|
||||
@@ -291,6 +291,7 @@
|
||||
<a-select-option value="20">20</a-select-option>
|
||||
<a-select-option value="50">50</a-select-option>
|
||||
<a-select-option value="100">100</a-select-option>
|
||||
<a-select-option value="500">500</a-select-option>
|
||||
</a-select>
|
||||
<a-select size="small" v-model="logModal.level" style="width:95px;"
|
||||
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
padding: .5rem 1rem;
|
||||
text-align: center;
|
||||
background: rgb(255 145 0 / 15%);
|
||||
margin: 1.5rem 2.5rem 0rem 2.5rem;
|
||||
margin: 1.5rem 2.5rem 0rem;
|
||||
border-radius: .5rem;
|
||||
transition: all 0.5s;
|
||||
animation: signal 3s cubic-bezier(0.18, 0.89, 0.32, 1.28) infinite;
|
||||
@@ -138,7 +138,7 @@
|
||||
<setting-list-item type="text" title='{{ i18n "pages.settings.publicKeyPath"}}' desc='{{ i18n "pages.settings.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.settings.privateKeyPath"}}' desc='{{ i18n "pages.settings.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.settings.panelUrlPath"}}' desc='{{ i18n "pages.settings.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="0"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="60"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.pageSize" }}' desc='{{ i18n "pages.settings.pageSizeDesc" }}' v-model="allSetting.pageSize" :min="0" :step="5"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.expireTimeDiff" }}' desc='{{ i18n "pages.settings.expireTimeDiffDesc" }}' v-model="allSetting.expireDiff" :min="0"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.trafficDiff" }}' desc='{{ i18n "pages.settings.trafficDiffDesc" }}' v-model="allSetting.trafficDiff" :min="0"></setting-list-item>
|
||||
@@ -246,6 +246,7 @@
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyLogin" }}' desc='{{ i18n "pages.settings.tgNotifyLoginDesc" }}' v-model="allSetting.tgBotLoginNotify"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.tgNotifyCpu" }}' desc='{{ i18n "pages.settings.tgNotifyCpuDesc" }}' v-model="allSetting.tgCpu" :min="0" :max="100"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.settings.telegramProxy"}}' desc='{{ i18n "pages.settings.telegramProxyDesc"}}' v-model="allSetting.tgBotProxy" placeholder="socks5://user:pass@host:port"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.settings.telegramAPIServer"}}' desc='{{ i18n "pages.settings.telegramAPIServerDesc"}}' v-model="allSetting.tgBotAPIServer" placeholder="https://api.example.com"></setting-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
@@ -305,20 +306,38 @@
|
||||
<a-list-item style="padding: 20px">
|
||||
<a-row>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta title='Noise'>
|
||||
<template slot="description">{{ i18n "pages.settings.noiseDesc"}}</template>
|
||||
<a-list-item-meta title='Noises'>
|
||||
<template slot="description">{{ i18n "pages.settings.noisesDesc"}}</template>
|
||||
</a-list-item-meta>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-switch v-model="noise"></a-switch>
|
||||
<a-switch v-model="noises"></a-switch>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-collapse v-if="noise" style="margin-top: 14px;">
|
||||
<a-collapse-panel header='{{ i18n "pages.settings.noiseSett"}}' v-if="noise">
|
||||
<setting-list-item style="padding: 10px 20px" type="text" title='Packet (ms)' v-model="noisePacket" placeholder="rand:5-10"></setting-list-item>
|
||||
<setting-list-item style="padding: 10px 20px" type="text" title='Delay (ms)' v-model="noiseDelay" placeholder="10-20"></setting-list-item>
|
||||
<a-collapse v-if="noises" style="margin-top: 14px;">
|
||||
<a-collapse-panel v-for="(noise, index) in noisesArray" :key="index" :header="`Noise ${index + 1}`">
|
||||
<a-list-item style="padding: 10px 20px">
|
||||
<a-row>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta title='Type'></a-list-item-meta>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-select :value="noise.type" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
@change="(value) => updateNoiseType(index, value)">
|
||||
<a-select-option :value="p" :label="p" v-for="p in ['rand', 'base64', 'str']" :key="p">
|
||||
[[ p ]] </a-select-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<setting-list-item style="padding: 10px 20px" type="text" title='Packet' :value="noise.packet"
|
||||
@input="(value) => updateNoisePacket(index, value)" placeholder="5-10"></setting-list-item>
|
||||
<setting-list-item style="padding: 10px 20px" type="text" title='Delay (ms)' :value="noise.delay"
|
||||
@input="(value) => updateNoiseDelay(index, value)" placeholder="10-20"></setting-list-item>
|
||||
<a-button v-if="noisesArray.length > 1" type="danger" @click="removeNoise(index)">Remove</a-button>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
<a-button v-if="noises" type="primary" @click="addNoise" style="margin-top: 10px">Add Noise</a-button>
|
||||
</a-list-item>
|
||||
<a-list-item style="padding: 20px">
|
||||
<a-row>
|
||||
@@ -362,9 +381,14 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-collapse v-if="enableDirect" style="margin-top: 14px;">
|
||||
<a-collapse-panel header='{{ i18n "pages.settings.directSett"}}'>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.directips"}}'>
|
||||
<a-list-item style="padding: 10px 20px">
|
||||
<a-checkbox-group v-model="directCountries" name="Countries" :options="countryOptions"></a-checkbox-group>
|
||||
<a-checkbox-group v-model="directIPs" :options="IPsOptions"></a-checkbox-group>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.directdomains"}}'>
|
||||
<a-list-item style="padding: 10px 20px">
|
||||
<a-checkbox-group v-model="directDomains" :options="DomainsOptions"></a-checkbox-group>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
@@ -419,15 +443,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultNoise: {
|
||||
tag: "noise",
|
||||
defaultNoises: {
|
||||
tag: "noises",
|
||||
protocol: "freedom",
|
||||
settings: {
|
||||
domainStrategy: "AsIs",
|
||||
noise: {
|
||||
packet: "rand:5-10",
|
||||
delay: "10-20",
|
||||
}
|
||||
noises: [
|
||||
{ type: "rand", packet: "10-20", delay: "10-16" },
|
||||
],
|
||||
},
|
||||
},
|
||||
defaultMux: {
|
||||
@@ -441,27 +464,37 @@
|
||||
type: "field",
|
||||
outboundTag: "direct",
|
||||
domain: [
|
||||
"geosite:category-ir",
|
||||
"geosite:cn"
|
||||
],
|
||||
"enabled": true
|
||||
"geosite:category-ir"
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "field",
|
||||
outboundTag: "direct",
|
||||
ip: [
|
||||
"geoip:private",
|
||||
"geoip:ir",
|
||||
"geoip:cn"
|
||||
],
|
||||
enabled: true
|
||||
"geoip:ir"
|
||||
]
|
||||
},
|
||||
],
|
||||
countryOptions: [
|
||||
{ label: 'Private IP/Domain', value: 'private' },
|
||||
IPsOptions: [
|
||||
{ label: 'Private IP', value: 'private' },
|
||||
{ label: '🇮🇷 Iran', value: 'ir' },
|
||||
{ label: '🇨🇳 China', value: 'cn' },
|
||||
{ label: '🇷🇺 Russia', value: 'ru' },
|
||||
{ label: '🇻🇳 Vietnam', value: 'vn' },
|
||||
{ label: '🇪🇸 Spain', value: 'es' },
|
||||
{ label: '🇮🇩 Indonesia', value: 'id' },
|
||||
{ label: '🇺🇦 Ukraine', value: 'ua' },
|
||||
{ label: '🇹🇷 Türkiye', value: 'tr' },
|
||||
{ label: '🇧🇷 Brazil', value: 'br' },
|
||||
],
|
||||
DomainsOptions: [
|
||||
{ label: '🇮🇷 Iran', value: 'ir' },
|
||||
{ label: '🇨🇳 China', value: 'cn' },
|
||||
{ label: '🇷🇺 Russia', value: 'ru' },
|
||||
{ label: 'Apple', value: 'apple' },
|
||||
{ label: 'Meta', value: 'meta' },
|
||||
{ label: 'Google', value: 'google' },
|
||||
],
|
||||
get remarkModel() {
|
||||
rm = this.allSetting.remarkModel;
|
||||
@@ -591,6 +624,30 @@
|
||||
this.user.loginSecret = "";
|
||||
}
|
||||
},
|
||||
addNoise() {
|
||||
const newNoise = { type: "rand", packet: "10-20", delay: "10-16" };
|
||||
this.noisesArray = [...this.noisesArray, newNoise];
|
||||
},
|
||||
removeNoise(index) {
|
||||
const newNoises = [...this.noisesArray];
|
||||
newNoises.splice(index, 1);
|
||||
this.noisesArray = newNoises;
|
||||
},
|
||||
updateNoiseType(index, value) {
|
||||
const updatedNoises = [...this.noisesArray];
|
||||
updatedNoises[index] = { ...updatedNoises[index], type: value };
|
||||
this.noisesArray = updatedNoises;
|
||||
},
|
||||
updateNoisePacket(index, value) {
|
||||
const updatedNoises = [...this.noisesArray];
|
||||
updatedNoises[index] = { ...updatedNoises[index], packet: value };
|
||||
this.noisesArray = updatedNoises;
|
||||
},
|
||||
updateNoiseDelay(index, value) {
|
||||
const updatedNoises = [...this.noisesArray];
|
||||
updatedNoises[index] = { ...updatedNoises[index], delay: value };
|
||||
this.noisesArray = updatedNoises;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
fragment: {
|
||||
@@ -629,29 +686,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
noise: {
|
||||
get: function () { return this.allSetting?.subJsonNoise != ""; },
|
||||
set: function (v) {
|
||||
this.allSetting.subJsonNoise = v ? JSON.stringify(this.defaultNoise) : "";
|
||||
}
|
||||
},
|
||||
noisePacket: {
|
||||
get: function () { return this.noise ? JSON.parse(this.allSetting.subJsonNoise).settings.noise.packet : ""; },
|
||||
set: function (v) {
|
||||
if (v != "") {
|
||||
newNoise = JSON.parse(this.allSetting.subJsonNoise);
|
||||
newNoise.settings.noise.packet = v;
|
||||
this.allSetting.subJsonNoise = JSON.stringify(newNoise);
|
||||
noises: {
|
||||
get() {
|
||||
return this.allSetting?.subJsonNoises != "";
|
||||
},
|
||||
set(v) {
|
||||
if (v) {
|
||||
this.allSetting.subJsonNoises = JSON.stringify(this.defaultNoises);
|
||||
} else {
|
||||
this.allSetting.subJsonNoises = "";
|
||||
}
|
||||
}
|
||||
},
|
||||
noiseDelay: {
|
||||
get: function () { return this.noise ? JSON.parse(this.allSetting.subJsonNoise).settings.noise.delay : ""; },
|
||||
set: function (v) {
|
||||
if (v != "") {
|
||||
newNoise = JSON.parse(this.allSetting.subJsonNoise);
|
||||
newNoise.settings.noise.delay = v;
|
||||
this.allSetting.subJsonNoise = JSON.stringify(newNoise);
|
||||
noisesArray: {
|
||||
get() {
|
||||
return this.noises ? JSON.parse(this.allSetting.subJsonNoises).settings.noises : [];
|
||||
},
|
||||
set(value) {
|
||||
if (this.noises) {
|
||||
const newNoises = JSON.parse(this.allSetting.subJsonNoises);
|
||||
newNoises.settings.noises = value;
|
||||
this.allSetting.subJsonNoises = JSON.stringify(newNoises);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -691,29 +746,67 @@
|
||||
this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : "";
|
||||
}
|
||||
},
|
||||
directCountries: {
|
||||
directIPs: {
|
||||
get: function () {
|
||||
if (!this.enableDirect) return [];
|
||||
rules = JSON.parse(this.allSetting.subJsonRules);
|
||||
return Array.isArray(rules) ? rules[1].ip.map(d => d.replace("geoip:", "")) : [];
|
||||
const rules = JSON.parse(this.allSetting.subJsonRules);
|
||||
if (!Array.isArray(rules)) return [];
|
||||
const ipRule = rules.find(r => r.ip);
|
||||
return ipRule?.ip.map(d => d.replace("geoip:", "")) ?? [];
|
||||
},
|
||||
set: function (v) {
|
||||
rules = JSON.parse(this.allSetting.subJsonRules);
|
||||
let rules = JSON.parse(this.allSetting.subJsonRules);
|
||||
if (!Array.isArray(rules)) return;
|
||||
rules[0].domain = [];
|
||||
rules[1].ip = [];
|
||||
v.forEach(d => {
|
||||
let category = '';
|
||||
if (["cn", "private"].includes(d)) {
|
||||
category = "";
|
||||
} else if (d === 'ru') {
|
||||
category = "category-gov-";
|
||||
} else {
|
||||
category = "category-";
|
||||
|
||||
if (v.length == 0) {
|
||||
rules = rules.filter(r => !r.ip);
|
||||
} else {
|
||||
let ruleIndex = rules.findIndex(r => r.ip);
|
||||
if (ruleIndex == -1) ruleIndex = rules.push(this.defaultRules[1]) - 1;
|
||||
|
||||
rules[ruleIndex].ip = [];
|
||||
v.forEach(d => {
|
||||
rules[ruleIndex].ip.push("geoip:" + d);
|
||||
});
|
||||
}
|
||||
this.allSetting.subJsonRules = JSON.stringify(rules);
|
||||
}
|
||||
},
|
||||
directDomains: {
|
||||
get: function () {
|
||||
if (!this.enableDirect) return [];
|
||||
const rules = JSON.parse(this.allSetting.subJsonRules);
|
||||
if (!Array.isArray(rules)) return [];
|
||||
const domainRule = rules.find(r => r.domain);
|
||||
return domainRule?.domain.map(d => {
|
||||
if (d.startsWith("geosite:category-")) {
|
||||
return d.replace("geosite:category-", "");
|
||||
}
|
||||
rules[0].domain.push("geosite:" + category + d);
|
||||
rules[1].ip.push("geoip:" + d);
|
||||
});
|
||||
return d.replace("geosite:", "");
|
||||
})
|
||||
?? [];
|
||||
},
|
||||
set: function (v) {
|
||||
let rules = JSON.parse(this.allSetting.subJsonRules);
|
||||
if (!Array.isArray(rules)) return;
|
||||
|
||||
if (v.length == 0) {
|
||||
rules = rules.filter(r => !r.domain);
|
||||
} else {
|
||||
let ruleIndex = rules.findIndex(r => r.domain);
|
||||
if (ruleIndex == -1) ruleIndex = rules.push(this.defaultRules[0]) - 1;
|
||||
|
||||
rules[ruleIndex].domain = [];
|
||||
v.forEach(d => {
|
||||
let category = '';
|
||||
if (["cn", "apple", "meta", "google"].includes(d)) {
|
||||
category = "";
|
||||
} else if (["ru", "ir"].includes(d)) {
|
||||
category = "category-";
|
||||
}
|
||||
rules[ruleIndex].domain.push("geosite:" + category + d);
|
||||
});
|
||||
}
|
||||
this.allSetting.subJsonRules = JSON.stringify(rules);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
publicKey: peer.public_key,
|
||||
endpoint: peer.endpoint.host,
|
||||
}],
|
||||
kernelMode: false
|
||||
noKernelTun: false,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
font-size: 24px;
|
||||
}
|
||||
.ant-collapse-content-box>li {
|
||||
padding: 12px 0 0 0 !important;
|
||||
padding: 12px 0 0 !important;
|
||||
}
|
||||
.ant-list-item>li {
|
||||
padding: 10px 20px !important;
|
||||
@@ -163,8 +163,8 @@
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select v-model="setLogLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
|
||||
<a-select-option v-for="s in logLevel" :value="s">[[ s ]]</a-select-option>
|
||||
<a-select v-model="logLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
|
||||
<a-select-option v-for="s in log.loglevel" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
@@ -178,7 +178,8 @@
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select v-model="accessLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
|
||||
<a-select-option v-for="s in access" :key="s" :value="s">[[ s ]]</a-select-option>
|
||||
<a-select-option value=''>Empty</a-select-option>
|
||||
<a-select-option v-for="s in log.access" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
@@ -192,11 +193,28 @@
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select v-model="errorLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
|
||||
<a-select-option v-for="s in error" :key="s" :value="s">[[ s ]]</a-select-option>
|
||||
<a-select-option value=''>Empty</a-select-option>
|
||||
<a-select-option v-for="s in log.error" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row style="padding: 10px 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta title='{{ i18n "pages.xray.maskAddress" }}'
|
||||
description='{{ i18n "pages.xray.maskAddressDesc" }}'>
|
||||
</a-list-item-meta>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select v-model="maskAddressLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
|
||||
<a-select-option value=''>Empty</a-select-option>
|
||||
<a-select-option v-for="s in log.maskAddress" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.dnsLog"}}' desc='{{ i18n "pages.xray.dnsLogDesc"}}' v-model="dnslog"></setting-list-item>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.blockConfigs"}}'>
|
||||
@@ -210,85 +228,157 @@
|
||||
</a-row>
|
||||
<a-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.Torrent"}}' desc='{{ i18n "pages.xray.TorrentDesc"}}' v-model="torrentSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.PrivateIp"}}' desc='{{ i18n "pages.xray.PrivateIpDesc"}}' v-model="privateIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.Ads"}}' desc='{{ i18n "pages.xray.AdsDesc"}}' v-model="AdsSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.Family"}}' desc='{{ i18n "pages.xray.FamilyDesc"}}' v-model="familyProtectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.Security"}}' desc='{{ i18n "pages.xray.SecurityDesc"}}' v-model="SecuritySettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.Speedtest"}}' desc='{{ i18n "pages.xray.SpeedtestDesc"}}' v-model="SpeedTestSettings"></setting-list-item>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.blockCountryConfigs"}}'>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.basicRouting"}}'>
|
||||
<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.blockCountryConfigsDesc" }}
|
||||
{{ i18n "pages.xray.blockConnectionsConfigsDesc" }}
|
||||
</template>
|
||||
</a-alert>
|
||||
</a-row>
|
||||
<a-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.IRIp"}}' desc='{{ i18n "pages.xray.IRIpDesc"}}' v-model="IRIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.IRDomain"}}' desc='{{ i18n "pages.xray.IRDomainDesc"}}' v-model="IRDomainSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.ChinaIp"}}' desc='{{ i18n "pages.xray.ChinaIpDesc"}}' v-model="ChinaIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.ChinaDomain"}}' desc='{{ i18n "pages.xray.ChinaDomainDesc"}}' v-model="ChinaDomainSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.RussiaIp"}}' desc='{{ i18n "pages.xray.RussiaIpDesc"}}' v-model="RussiaIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.RussiaDomain"}}' desc='{{ i18n "pages.xray.RussiaDomainDesc"}}' v-model="RussiaDomainSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.VNIp"}}' desc='{{ i18n "pages.xray.VNIpDesc"}}' v-model="VNIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.VNDomain"}}' desc='{{ i18n "pages.xray.VNDomainDesc"}}' v-model="VNDomainSettings"></setting-list-item>
|
||||
<a-row style="padding: 0 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.blockips" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select mode="tags" v-model="blockedIPs" style="width: 100%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="p.value" :label="p.label"
|
||||
v-for="p in settingsData.IPsOptions"> [[ p.label ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 0 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.blockdomains" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select mode="tags" style="width: 100%"
|
||||
v-model="blockedDomains"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="p.value" :label="p.label"
|
||||
v-for="p in settingsData.BlockDomainsOptions"> [[ p.label ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.directCountryConfigs"}}'>
|
||||
<a-row :xs="24" :sm="24" :lg="12">
|
||||
<a-alert type="warning" style="text-align: center;">
|
||||
<a-alert type="warning" style="text-align: center; margin-top: 20px;">
|
||||
<template slot="message">
|
||||
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
|
||||
{{ i18n "pages.xray.directCountryConfigsDesc" }}
|
||||
{{ i18n "pages.xray.directConnectionsConfigsDesc" }}
|
||||
</template>
|
||||
</a-alert>
|
||||
</a-row>
|
||||
<a-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectIRIp"}}' desc='{{ i18n "pages.xray.DirectIRIpDesc"}}' v-model="IRIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectIRDomain"}}' desc='{{ i18n "pages.xray.DirectIRDomainDesc"}}' v-model="IRDomainDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectChinaIp"}}' desc='{{ i18n "pages.xray.DirectChinaIpDesc"}}' v-model="ChinaIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectChinaDomain"}}' desc='{{ i18n "pages.xray.DirectChinaDomainDesc"}}' v-model="ChinaDomainDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectRussiaIp"}}' desc='{{ i18n "pages.xray.DirectRussiaIpDesc"}}' v-model="RussiaIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectRussiaDomain"}}' desc='{{ i18n "pages.xray.DirectRussiaDomainDesc"}}' v-model="RussiaDomainDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectVNIp"}}' desc='{{ i18n "pages.xray.DirectVNIpDesc"}}' v-model="VNIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectVNDomain"}}' desc='{{ i18n "pages.xray.DirectVNDomainDesc"}}' v-model="VNDomainDirectSettings"></setting-list-item>
|
||||
<a-row style="padding: 0 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.directips" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select mode="tags" style="width: 100%"
|
||||
v-model="directIPs"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="p.value" :label="p.label"
|
||||
v-for="p in settingsData.IPsOptions"> [[ p.label ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 0 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.directdomains" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select mode="tags" style="width: 100%"
|
||||
v-model="directDomains"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="p.value" :label="p.label"
|
||||
v-for="p in settingsData.DomainsOptions"> [[ p.label ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.ipv4Configs"}}'>
|
||||
<a-row :xs="24" :sm="24" :lg="12">
|
||||
<a-alert type="warning" style="text-align: center;">
|
||||
<a-alert type="warning" style="text-align: center; margin-top: 20px;">
|
||||
<template slot="message">
|
||||
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
|
||||
{{ i18n "pages.xray.ipv4ConfigsDesc" }}
|
||||
{{ i18n "pages.xray.ipv4RoutingDesc" }}
|
||||
</template>
|
||||
</a-alert>
|
||||
</a-row>
|
||||
<a-list-item>
|
||||
<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-row style="padding: 0 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.ipv4Routing" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select mode="tags" style="width: 100%"
|
||||
v-model="ipv4Domains"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="p.value" :label="p.label"
|
||||
v-for="p in settingsData.ServicesOptions"> [[ p.label ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-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;">
|
||||
<a-alert type="warning" style="text-align: center; margin-top: 20px;">
|
||||
<template slot="message">
|
||||
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
|
||||
{{ i18n "pages.xray.warpConfigsDesc" }}
|
||||
{{ i18n "pages.xray.warpRoutingDesc" }}
|
||||
</template>
|
||||
</a-alert>
|
||||
</a-row>
|
||||
<a-list-item>
|
||||
<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>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.MetaWARP"}}' desc='{{ i18n "pages.xray.MetaWARPDesc"}}' v-model="MetaWARPSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.AppleWARP"}}' desc='{{ i18n "pages.xray.AppleWARPDesc"}}' v-model="AppleWARPSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.RedditWARP"}}' desc='{{ i18n "pages.xray.RedditWARPDesc"}}' v-model="RedditWARPSettings"></setting-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 0 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.warpRouting" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select mode="tags" style="width: 100%"
|
||||
v-model="warpDomains"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="p.value" :label="p.label"
|
||||
v-for="p in settingsData.ServicesOptions"> [[ p.label ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
</template>
|
||||
<a-button style="margin-left: 20px;" v-else type="primary" icon="cloud" @click="showWarp()">WARP</a-button>
|
||||
</a-list-item>
|
||||
@@ -569,86 +659,90 @@
|
||||
</a-radio-group>
|
||||
<textarea style="position:absolute; left: -800px;" id="obsSetting"></textarea>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="tpl-dns" tab='DNS' style="padding-top: 20px;" force-render="true">
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.dns.enable" }}' desc='{{ i18n "pages.xray.dns.enableDesc" }}' v-model="enableDNS"></setting-list-item>
|
||||
<a-tab-pane key="tpl-dns" tab='DNS' style="padding-top: 20px;" force-render="true">
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.dns.enable" }}'
|
||||
desc='{{ i18n "pages.xray.dns.enableDesc" }}' v-model="enableDNS"></setting-list-item>
|
||||
<template v-if="enableDNS">
|
||||
<setting-list-item style="padding: 10px 20px" type="text" title='{{ i18n "pages.xray.dns.tag" }}' desc='{{ i18n "pages.xray.dns.tagDesc" }}' v-model="dnsTag"></setting-list-item>
|
||||
<a-list-item style="padding: 10px 20px">
|
||||
<a-row>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta title='{{ i18n "pages.xray.dns.strategy" }}' description='{{ i18n "pages.xray.dns.strategyDesc" }}' />
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-select
|
||||
v-model="dnsStrategy"
|
||||
style="width: 100%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']">
|
||||
[[ l ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<a-divider>DNS</a-divider>
|
||||
<a-button type="primary" icon="plus" @click="addDNSServer()" style="margin-bottom: 10px;">{{ i18n "pages.xray.dns.add" }}</a-button>
|
||||
<a-table :columns="dnsColumns" bordered v-if="dnsServers.length>0"
|
||||
:row-key="r => r.key"
|
||||
:data-source="dnsServers"
|
||||
:scroll="isMobile ? {} : { x: 200 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||
<template slot="action" slot-scope="text,dns,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="editDNSServer(index)">
|
||||
<a-icon type="edit"></a-icon>
|
||||
{{ i18n "edit" }}
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="deleteDNSServer(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="dns,index">
|
||||
<span v-if="typeof dns == 'object'">[[ dns.address ]]</span>
|
||||
<span v-else>[[ dns ]]</span>
|
||||
</template>
|
||||
<template slot="domain" slot-scope="dns,index">
|
||||
<span v-if="typeof dns == 'object'">[[ dns.domains.join(",") ]]</span>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-divider>Fake DNS</a-divider>
|
||||
<a-button type="primary" icon="plus" @click="addFakedns()" style="margin-bottom: 10px;">{{ i18n "pages.xray.fakedns.add" }}</a-button>
|
||||
<a-table :columns="fakednsColumns" bordered v-if="fakeDns && fakeDns.length>0" :row-key="r => r.key"
|
||||
:data-source="fakeDns" :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||
<template slot="action" slot-scope="text,fakedns,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="editFakedns(index)">
|
||||
<a-icon type="edit"></a-icon>
|
||||
{{ i18n "edit" }}
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="deleteFakedns(index)">
|
||||
<span style="color: #FF4D4F">
|
||||
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
|
||||
</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
</a-table>
|
||||
<setting-list-item style="padding: 10px 20px" type="text" title='{{ i18n "pages.xray.dns.tag" }}'
|
||||
desc='{{ i18n "pages.xray.dns.tagDesc" }}' v-model="dnsTag"></setting-list-item>
|
||||
<a-list-item style="padding: 10px 20px">
|
||||
<a-row>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta title='{{ i18n "pages.xray.dns.strategy" }}'
|
||||
description='{{ i18n "pages.xray.dns.strategyDesc" }}' />
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-select v-model="dnsStrategy" style="width: 100%"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']">
|
||||
[[ l ]]
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<a-divider>DNS</a-divider>
|
||||
<a-button type="primary" icon="plus" @click="addDNSServer()" style="margin-bottom: 10px;">{{ i18n
|
||||
"pages.xray.dns.add" }}</a-button>
|
||||
<a-table :columns="dnsColumns" bordered v-if="dnsServers.length>0" :row-key="r => r.key"
|
||||
:data-source="dnsServers" :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||
<template slot="action" slot-scope="text,dns,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="editDNSServer(index)">
|
||||
<a-icon type="edit"></a-icon>
|
||||
{{ i18n "edit" }}
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="deleteDNSServer(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="dns,index">
|
||||
<span v-if="typeof dns == 'object'">[[ dns.address ]]</span>
|
||||
<span v-else>[[ dns ]]</span>
|
||||
</template>
|
||||
<template slot="domain" slot-scope="dns,index">
|
||||
<span v-if="typeof dns == 'object'">[[ dns.domains.join(",") ]]</span>
|
||||
</template>
|
||||
<template slot="expectIPs" slot-scope="dns,index">
|
||||
<span v-if="typeof dns == 'object'">[[ dns.expectIPs.join(",") ]]</span>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-divider>Fake DNS</a-divider>
|
||||
<a-button type="primary" icon="plus" @click="addFakedns()" style="margin-bottom: 10px;">{{ i18n
|
||||
"pages.xray.fakedns.add" }}</a-button>
|
||||
<a-table :columns="fakednsColumns" bordered v-if="fakeDns && fakeDns.length>0" :row-key="r => r.key"
|
||||
:data-source="fakeDns" :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||
<template slot="action" slot-scope="text,fakedns,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="editFakedns(index)">
|
||||
<a-icon type="edit"></a-icon>
|
||||
{{ i18n "edit" }}
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="deleteFakedns(index)">
|
||||
<span style="color: #FF4D4F">
|
||||
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
|
||||
</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</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' : ''">
|
||||
@@ -730,6 +824,7 @@
|
||||
{ title: "#", align: 'center', width: 20, scopedSlots: { customRender: 'action' } },
|
||||
{ title: '{{ i18n "pages.xray.outbound.address"}}', align: 'center', width: 50, scopedSlots: { customRender: 'address' } },
|
||||
{ title: '{{ i18n "pages.xray.dns.domains"}}', align: 'center', width: 50, scopedSlots: { customRender: 'domain' } },
|
||||
{ title: '{{ i18n "pages.xray.dns.expectIPs"}}', align: 'center', width: 50, scopedSlots: { customRender: 'expectIPs' } },
|
||||
];
|
||||
|
||||
const fakednsColumns = [
|
||||
@@ -791,57 +886,67 @@
|
||||
protocol: "freedom"
|
||||
},
|
||||
routingDomainStrategies: ["AsIs", "IPIfNonMatch", "IPOnDemand"],
|
||||
logLevel: ["none" , "debug" , "info" , "warning", "error"],
|
||||
access: [],
|
||||
error: [],
|
||||
log: {
|
||||
loglevel: ["none", "debug", "info", "warning", "error"],
|
||||
access: ["none", "./access.log"],
|
||||
error: ["none", "./error.log"],
|
||||
dnsLog: false,
|
||||
maskAddress: ["quarter", "half", "full"],
|
||||
},
|
||||
settingsData: {
|
||||
protocols: {
|
||||
bittorrent: ["bittorrent"],
|
||||
},
|
||||
ips: {
|
||||
local: ["geoip:private"],
|
||||
cn: ["geoip:cn"],
|
||||
ir: ["ext:geoip_IR.dat:ir"],
|
||||
ru: ["geoip:ru"],
|
||||
vn: ["ext:geoip_VN.dat:vn"],
|
||||
},
|
||||
domains: {
|
||||
ads: [
|
||||
"geosite:category-ads-all",
|
||||
"ext:geosite_IR.dat:category-ads-all"
|
||||
],
|
||||
security: [
|
||||
"ext:geosite_IR.dat:malware",
|
||||
"ext:geosite_IR.dat:phishing",
|
||||
"ext:geosite_IR.dat:cryptominers"
|
||||
],
|
||||
speedtest: ["geosite:speedtest"],
|
||||
openai: ["geosite:openai"],
|
||||
google: ["geosite:google"],
|
||||
spotify: ["geosite:spotify"],
|
||||
netflix: ["geosite:netflix"],
|
||||
meta: ["geosite:meta"],
|
||||
apple: ["geosite:apple"],
|
||||
reddit: ["geosite:reddit"],
|
||||
cn: [
|
||||
"geosite:cn",
|
||||
"regexp:.*\\.cn$"
|
||||
],
|
||||
ru: [
|
||||
"geosite:category-gov-ru",
|
||||
"regexp:.*\\.ru$"
|
||||
],
|
||||
ir: [
|
||||
"regexp:.*\\.ir$",
|
||||
"regexp:.*\\.xn--mgba3a4f16a$", // .ایران
|
||||
"ext:geosite_IR.dat:ir"
|
||||
],
|
||||
vn: [
|
||||
"regexp:.*\\.vn$",
|
||||
"ext:geosite_VN.dat:vn",
|
||||
"ext:geosite_VN.dat:ads"
|
||||
]
|
||||
},
|
||||
IPsOptions: [
|
||||
{ label: 'Private IPs', value: 'geoip:private' },
|
||||
{ label: '🇮🇷 Iran', value: 'ext:geoip_IR.dat:ir' },
|
||||
{ label: '🇨🇳 China', value: 'geoip:cn' },
|
||||
{ label: '🇷🇺 Russia', value: 'geoip:ru' },
|
||||
{ label: '🇻🇳 Vietnam', value: 'ext:geoip_VN.dat:vn' },
|
||||
{ label: '🇪🇸 Spain', value: 'geoip:es' },
|
||||
{ label: '🇮🇩 Indonesia', value: 'geoip:id' },
|
||||
{ label: '🇺🇦 Ukraine', value: 'geoip:ua' },
|
||||
{ label: '🇹🇷 Türkiye', value: 'geoip:tr' },
|
||||
{ label: '🇧🇷 Brazil', value: 'geoip:br' },
|
||||
],
|
||||
DomainsOptions: [
|
||||
{ label: '🇮🇷 Iran', value: 'ext:geosite_IR.dat:ir' },
|
||||
{ label: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' },
|
||||
{ label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' },
|
||||
{ label: '🇨🇳 China', value: 'geosite:cn' },
|
||||
{ label: '🇨🇳 .cn', value: 'regexp:.*\\.cn$' },
|
||||
{ label: '🇷🇺 Russia', value: 'geosite:category-ru' },
|
||||
{ label: '🇷🇺 .ru', value: 'regexp:.*\\.ru' },
|
||||
{ label: '🇻🇳 Vietnam', value: 'ext:geosite_VN.dat:vn' },
|
||||
{ label: '🇻🇳 .vn', value: 'regexp:.*\\.vn$' },
|
||||
],
|
||||
BlockDomainsOptions: [
|
||||
{ label: 'Ads All', value: 'geosite:category-ads-all' },
|
||||
{ label: 'Ads IR 🇮🇷', value: 'ext:geosite_IR.dat:category-ads-all' },
|
||||
{ label: 'Ads VN 🇻🇳', value: 'ext:geosite_VN.dat:ads' },
|
||||
{ label: 'Malware 🇮🇷', value: 'ext:geosite_IR.dat:malware' },
|
||||
{ label: 'Phishing 🇮🇷', value: 'ext:geosite_IR.dat:phishing' },
|
||||
{ label: 'Cryptominers 🇮🇷', value: 'ext:geosite_IR.dat:cryptominers' },
|
||||
{ label: '🇮🇷 Iran', value: 'ext:geosite_IR.dat:ir' },
|
||||
{ label: '🇮🇷 .ir', value: 'regexp:.*\\.ir$' },
|
||||
{ label: '🇮🇷 .ایران', value: 'regexp:.*\\.xn--mgba3a4f16a$' },
|
||||
{ label: '🇨🇳 China', value: 'geosite:cn' },
|
||||
{ label: '🇨🇳 .cn', value: 'regexp:.*\\.cn$' },
|
||||
{ label: '🇷🇺 Russia', value: 'geosite:category-ru' },
|
||||
{ label: '🇷🇺 .ru', value: 'regexp:.*\\.ru' },
|
||||
{ label: '🇻🇳 Vietnam', value: 'ext:geosite_VN.dat:vn' },
|
||||
{ label: '🇻🇳 .vn', value: 'regexp:.*\\.vn$' },
|
||||
],
|
||||
ServicesOptions: [
|
||||
{ label: 'Apple', value: 'geosite:apple' },
|
||||
{ label: 'Meta', value: 'geosite:meta' },
|
||||
{ label: 'Google', value: 'geosite:google' },
|
||||
{ label: 'OpenAI', value: 'geosite:openai' },
|
||||
{ label: 'Spotify', value: 'geosite:spotify' },
|
||||
{ label: 'Netflix', value: 'geosite:netflix' },
|
||||
{ label: 'Reddit', value: 'geosite:reddit' },
|
||||
{ label: 'Speedtest', value: 'geosite:speedtest' },
|
||||
],
|
||||
familyProtectDNS: {
|
||||
"servers": [
|
||||
"1.1.1.3", // https://developers.cloudflare.com/1.1.1.1/setup/
|
||||
@@ -1519,27 +1624,11 @@
|
||||
templateSettings: {
|
||||
get: function () {
|
||||
const parsedSettings = this.xraySetting ? JSON.parse(this.xraySetting) : null;
|
||||
let accessLogPath = "./access.log";
|
||||
let errorLogPath = "./error.log";
|
||||
|
||||
if (parsedSettings && parsedSettings.log) {
|
||||
if (parsedSettings.log.access && parsedSettings.log.access !== "none") {
|
||||
accessLogPath = parsedSettings.log.access;
|
||||
}
|
||||
if (parsedSettings.log.error && parsedSettings.log.error !== "none") {
|
||||
errorLogPath = parsedSettings.log.error;
|
||||
}
|
||||
}
|
||||
|
||||
this.access = ["none", accessLogPath];
|
||||
this.error = ["none", errorLogPath];
|
||||
return parsedSettings;
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue && newValue.log) {
|
||||
if (newValue) {
|
||||
this.xraySetting = JSON.stringify(newValue, null, 2);
|
||||
this.access = ["none", newValue.log.access || "./access.log"];
|
||||
this.error = ["none", newValue.log.error || "./error.log"];
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -1688,7 +1777,7 @@
|
||||
this.templateSettings = newTemplateSettings;
|
||||
}
|
||||
},
|
||||
setLogLevel: {
|
||||
logLevel: {
|
||||
get: function () {
|
||||
if (!this.templateSettings || !this.templateSettings.log || !this.templateSettings.log.loglevel) return "warning";
|
||||
return this.templateSettings.log.loglevel;
|
||||
@@ -1721,6 +1810,28 @@
|
||||
this.templateSettings = newTemplateSettings;
|
||||
}
|
||||
},
|
||||
dnslog: {
|
||||
get: function () {
|
||||
if (!this.templateSettings || !this.templateSettings.log || !this.templateSettings.log.dnsLog) return false;
|
||||
return this.templateSettings.log.dnsLog;
|
||||
},
|
||||
set: function (newValue) {
|
||||
newTemplateSettings = this.templateSettings;
|
||||
newTemplateSettings.log.dnsLog = newValue;
|
||||
this.templateSettings = newTemplateSettings;
|
||||
}
|
||||
},
|
||||
maskAddressLog: {
|
||||
get: function () {
|
||||
if (!this.templateSettings || !this.templateSettings.log || !this.templateSettings.log.maskAddress) return "";
|
||||
return this.templateSettings.log.maskAddress;
|
||||
},
|
||||
set: function (newValue) {
|
||||
newTemplateSettings = this.templateSettings;
|
||||
newTemplateSettings.log.maskAddress = newValue;
|
||||
this.templateSettings = newTemplateSettings;
|
||||
}
|
||||
},
|
||||
blockedIPs: {
|
||||
get: function () {
|
||||
return this.templateRuleGetter({ outboundTag: "blocked", property: "ip" });
|
||||
@@ -1792,54 +1903,6 @@
|
||||
}
|
||||
},
|
||||
},
|
||||
privateIpSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.local, this.blockedIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedIPs = [...this.blockedIPs, ...this.settingsData.ips.local];
|
||||
} else {
|
||||
this.blockedIPs = this.blockedIPs.filter(data => !this.settingsData.ips.local.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
AdsSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.ads, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.ads];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.ads.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
SecuritySettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.security, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.security];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.security.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
SpeedTestSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.speedtest, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.speedtest];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.speedtest.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
familyProtectSettings: {
|
||||
get: function () {
|
||||
if (!this.templateSettings || !this.templateSettings.dns || !this.templateSettings.dns.servers) return false;
|
||||
@@ -1855,311 +1918,11 @@
|
||||
this.templateSettings = newTemplateSettings;
|
||||
},
|
||||
},
|
||||
GoogleIPv4Settings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.google, this.ipv4Domains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.ipv4Domains = [...this.ipv4Domains, ...this.settingsData.domains.google];
|
||||
} else {
|
||||
this.ipv4Domains = this.ipv4Domains.filter(data => !this.settingsData.domains.google.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
NetflixIPv4Settings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.netflix, this.ipv4Domains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.ipv4Domains = [...this.ipv4Domains, ...this.settingsData.domains.netflix];
|
||||
} else {
|
||||
this.ipv4Domains = this.ipv4Domains.filter(data => !this.settingsData.domains.netflix.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
IRIpSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.ir, this.blockedIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedIPs = [...this.blockedIPs, ...this.settingsData.ips.ir];
|
||||
} else {
|
||||
this.blockedIPs = this.blockedIPs.filter(data => !this.settingsData.ips.ir.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
IRDomainSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.ir, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.ir];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.ir.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
ChinaIpSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.cn, this.blockedIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedIPs = [...this.blockedIPs, ...this.settingsData.ips.cn];
|
||||
} else {
|
||||
this.blockedIPs = this.blockedIPs.filter(data => !this.settingsData.ips.cn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
ChinaDomainSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.cn, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.cn];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.cn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
RussiaIpSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.ru, this.blockedIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedIPs = [...this.blockedIPs, ...this.settingsData.ips.ru];
|
||||
} else {
|
||||
this.blockedIPs = this.blockedIPs.filter(data => !this.settingsData.ips.ru.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
RussiaDomainSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.ru, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.ru];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.ru.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
VNIpSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.vn, this.blockedIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedIPs = [...this.blockedIPs, ...this.settingsData.ips.vn];
|
||||
} else {
|
||||
this.blockedIPs = this.blockedIPs.filter(data => !this.settingsData.ips.vn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
VNDomainSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.vn, this.blockedDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.vn];
|
||||
} else {
|
||||
this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.vn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
IRIpDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.ir, this.directIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directIPs = [...this.directIPs, ...this.settingsData.ips.ir];
|
||||
} else {
|
||||
this.directIPs = this.directIPs.filter(data => !this.settingsData.ips.ir.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
IRDomainDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.ir, this.directDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directDomains = [...this.directDomains, ...this.settingsData.domains.ir];
|
||||
} else {
|
||||
this.directDomains = this.directDomains.filter(data => !this.settingsData.domains.ir.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
ChinaIpDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.cn, this.directIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directIPs = [...this.directIPs, ...this.settingsData.ips.cn];
|
||||
} else {
|
||||
this.directIPs = this.directIPs.filter(data => !this.settingsData.ips.cn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
ChinaDomainDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.cn, this.directDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directDomains = [...this.directDomains, ...this.settingsData.domains.cn];
|
||||
} else {
|
||||
this.directDomains = this.directDomains.filter(data => !this.settingsData.domains.cn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
RussiaIpDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.ru, this.directIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directIPs = [...this.directIPs, ...this.settingsData.ips.ru];
|
||||
} else {
|
||||
this.directIPs = this.directIPs.filter(data => !this.settingsData.ips.ru.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
RussiaDomainDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.ru, this.directDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directDomains = [...this.directDomains, ...this.settingsData.domains.ru];
|
||||
} else {
|
||||
this.directDomains = this.directDomains.filter(data => !this.settingsData.domains.ru.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
VNIpDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.vn, this.directIPs);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directIPs = [...this.directIPs, ...this.settingsData.ips.vn];
|
||||
} else {
|
||||
this.directIPs = this.directIPs.filter(data => !this.settingsData.ips.vn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
VNDomainDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.vn, this.directDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.directDomains = [...this.directDomains, ...this.settingsData.domains.vn];
|
||||
} else {
|
||||
this.directDomains = this.directDomains.filter(data => !this.settingsData.domains.vn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
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));
|
||||
}
|
||||
},
|
||||
},
|
||||
MetaWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.meta, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.meta];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.meta.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
AppleWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.apple, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.apple];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.apple.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
RedditWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.reddit, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.reddit];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.reddit.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));
|
||||
}
|
||||
},
|
||||
},
|
||||
enableDNS: {
|
||||
get: function () {
|
||||
return this.templateSettings ? this.templateSettings.dns != null : false;
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"x-ui/database"
|
||||
@@ -36,15 +35,16 @@ func (j *CheckClientIpJob) Run() {
|
||||
}
|
||||
|
||||
shouldClearAccessLog := false
|
||||
iplimitActive := j.hasLimitIp()
|
||||
f2bInstalled := j.checkFail2BanInstalled()
|
||||
isAccessLogAvailable := j.checkAccessLogAvailable()
|
||||
isAccessLogAvailable := j.checkAccessLogAvailable(iplimitActive)
|
||||
|
||||
if j.hasLimitIp() {
|
||||
if iplimitActive {
|
||||
if f2bInstalled && isAccessLogAvailable {
|
||||
shouldClearAccessLog = j.processLogFile()
|
||||
} else {
|
||||
if !f2bInstalled {
|
||||
logger.Warning("[iplimit] fail2ban is not installed. IP limiting may not work properly.")
|
||||
logger.Warning("[LimitIP] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,23 +58,18 @@ func (j *CheckClientIpJob) clearAccessLog() {
|
||||
logAccessP, err := os.OpenFile(xray.GetAccessPersistentLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
|
||||
j.checkError(err)
|
||||
|
||||
// get access log path to open it
|
||||
accessLogPath, err := xray.GetAccessLogPath()
|
||||
j.checkError(err)
|
||||
|
||||
// reopen the access log file for reading
|
||||
file, err := os.Open(accessLogPath)
|
||||
j.checkError(err)
|
||||
|
||||
// copy access log content to persistent file
|
||||
_, err = io.Copy(logAccessP, file)
|
||||
j.checkError(err)
|
||||
|
||||
// close the file after copying content
|
||||
logAccessP.Close()
|
||||
file.Close()
|
||||
|
||||
// clean access log
|
||||
err = os.Truncate(accessLogPath, 0)
|
||||
j.checkError(err)
|
||||
j.lastClear = time.Now().Unix()
|
||||
@@ -110,58 +105,59 @@ func (j *CheckClientIpJob) hasLimitIp() bool {
|
||||
}
|
||||
|
||||
func (j *CheckClientIpJob) processLogFile() bool {
|
||||
accessLogPath, err := xray.GetAccessLogPath()
|
||||
j.checkError(err)
|
||||
|
||||
file, err := os.Open(accessLogPath)
|
||||
j.checkError(err)
|
||||
ipRegex := regexp.MustCompile(`from \[?([0-9a-fA-F:.]+)\]?:\d+ accepted`)
|
||||
emailRegex := regexp.MustCompile(`email: (.+)$`)
|
||||
|
||||
InboundClientIps := make(map[string][]string)
|
||||
accessLogPath, _ := xray.GetAccessLogPath()
|
||||
file, _ := os.Open(accessLogPath)
|
||||
defer file.Close()
|
||||
|
||||
inboundClientIps := make(map[string]map[string]struct{}, 100)
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
ipRegx, _ := regexp.Compile(`from \[?([0-9a-fA-F:.]+)\]?:\d+ accepted`)
|
||||
emailRegx, _ := regexp.Compile(`email:.+`)
|
||||
|
||||
matches := ipRegx.FindStringSubmatch(line)
|
||||
if len(matches) > 1 {
|
||||
ip := matches[1]
|
||||
if ip == "127.0.0.1" || ip == "::1" {
|
||||
continue
|
||||
}
|
||||
|
||||
matchesEmail := emailRegx.FindString(line)
|
||||
if matchesEmail == "" {
|
||||
continue
|
||||
}
|
||||
matchesEmail = strings.TrimSpace(strings.Split(matchesEmail, "email: ")[1])
|
||||
|
||||
if InboundClientIps[matchesEmail] != nil {
|
||||
if j.contains(InboundClientIps[matchesEmail], ip) {
|
||||
continue
|
||||
}
|
||||
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
|
||||
} else {
|
||||
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
|
||||
}
|
||||
ipMatches := ipRegex.FindStringSubmatch(line)
|
||||
if len(ipMatches) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
ip := ipMatches[1]
|
||||
|
||||
if ip == "127.0.0.1" || ip == "::1" {
|
||||
continue
|
||||
}
|
||||
|
||||
emailMatches := emailRegex.FindStringSubmatch(line)
|
||||
if len(emailMatches) < 2 {
|
||||
continue
|
||||
}
|
||||
email := emailMatches[1]
|
||||
|
||||
if _, exists := inboundClientIps[email]; !exists {
|
||||
inboundClientIps[email] = make(map[string]struct{})
|
||||
}
|
||||
inboundClientIps[email][ip] = struct{}{}
|
||||
}
|
||||
|
||||
j.checkError(scanner.Err())
|
||||
file.Close()
|
||||
|
||||
shouldCleanLog := false
|
||||
for email, uniqueIps := range inboundClientIps {
|
||||
|
||||
for clientEmail, ips := range InboundClientIps {
|
||||
inboundClientIps, err := j.getInboundClientIps(clientEmail)
|
||||
sort.Strings(ips)
|
||||
if err != nil {
|
||||
j.addInboundClientIps(clientEmail, ips)
|
||||
} else {
|
||||
shouldCleanLog = j.updateInboundClientIps(inboundClientIps, clientEmail, ips)
|
||||
ips := make([]string, 0, len(uniqueIps))
|
||||
for ip := range uniqueIps {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
sort.Strings(ips)
|
||||
|
||||
inboundClientIps, err := j.getInboundClientIps(email)
|
||||
if err != nil {
|
||||
j.addInboundClientIps(email, ips)
|
||||
continue
|
||||
}
|
||||
|
||||
shouldCleanLog = j.updateInboundClientIps(inboundClientIps, email, ips) || shouldCleanLog
|
||||
}
|
||||
|
||||
return shouldCleanLog
|
||||
@@ -174,19 +170,20 @@ func (j *CheckClientIpJob) checkFail2BanInstalled() bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (j *CheckClientIpJob) checkAccessLogAvailable() bool {
|
||||
isAvailable := true
|
||||
func (j *CheckClientIpJob) checkAccessLogAvailable(iplimitActive bool) bool {
|
||||
accessLogPath, err := xray.GetAccessLogPath()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch accessLogPath {
|
||||
case "none", "":
|
||||
isAvailable = false
|
||||
if accessLogPath == "none" || accessLogPath == "" {
|
||||
if iplimitActive {
|
||||
logger.Warning("[LimitIP] Access log path is not set, Please configure the access log path in Xray configs.")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return isAvailable
|
||||
return true
|
||||
}
|
||||
|
||||
func (j *CheckClientIpJob) checkError(e error) {
|
||||
@@ -251,7 +248,6 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||
inboundClientIps.ClientEmail = clientEmail
|
||||
inboundClientIps.Ips = string(jsonIps)
|
||||
|
||||
// Fetch inbound settings by client email
|
||||
inbound, err := j.getInboundByEmail(clientEmail)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to fetch inbound settings for email %s: %s", clientEmail, err)
|
||||
@@ -263,14 +259,12 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||
return false
|
||||
}
|
||||
|
||||
// Unmarshal settings to get client limits
|
||||
settings := map[string][]model.Client{}
|
||||
json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
clients := settings["clients"]
|
||||
shouldCleanLog := false
|
||||
j.disAllowedIps = []string{}
|
||||
|
||||
// Open log file for IP limits
|
||||
logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to open IP limit log file: %s", err)
|
||||
@@ -280,7 +274,6 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||
log.SetOutput(logIpFile)
|
||||
log.SetFlags(log.LstdFlags)
|
||||
|
||||
// Check client IP limits
|
||||
for _, client := range clients {
|
||||
if client.Email == clientEmail {
|
||||
limitIp := client.LimitIP
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
"log": {
|
||||
"access": "none",
|
||||
"dnsLog": false,
|
||||
"error": "./error.log",
|
||||
"loglevel": "warning"
|
||||
"error": "",
|
||||
"loglevel": "warning",
|
||||
"maskAddress": ""
|
||||
},
|
||||
"api": {
|
||||
"tag": "api",
|
||||
@@ -29,7 +30,9 @@
|
||||
"tag": "direct",
|
||||
"protocol": "freedom",
|
||||
"settings": {
|
||||
"domainStrategy": "UseIP"
|
||||
"domainStrategy": "AsIs",
|
||||
"redirect": "",
|
||||
"noises": []
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,9 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -101,8 +99,9 @@ func (s *InboundService) getAllEmails() ([]string, error) {
|
||||
}
|
||||
|
||||
func (s *InboundService) contains(slice []string, str string) bool {
|
||||
lowerStr := strings.ToLower(str)
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
if strings.ToLower(s) == lowerStr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -331,6 +330,7 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
|
||||
oldInbound.Settings = inbound.Settings
|
||||
oldInbound.StreamSettings = inbound.StreamSettings
|
||||
oldInbound.Sniffing = inbound.Sniffing
|
||||
oldInbound.Allocate = inbound.Allocate
|
||||
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
||||
oldInbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
||||
} else {
|
||||
@@ -413,12 +413,6 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
email := clients[0].Email
|
||||
valid, err := validateEmail(email)
|
||||
if !valid {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||
if err != nil {
|
||||
@@ -594,8 +588,12 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
|
||||
logger.Debug("Client deleted by api:", email)
|
||||
needRestart = false
|
||||
} else {
|
||||
logger.Debug("Unable to del client by api:", err1)
|
||||
needRestart = true
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", email)) {
|
||||
logger.Debug("User is already deleted. Nothing to do more...")
|
||||
} else {
|
||||
logger.Debug("Error in deleting client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
s.xrayApi.Close()
|
||||
}
|
||||
@@ -609,12 +607,6 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
return false, err
|
||||
}
|
||||
|
||||
email := clients[0].Email
|
||||
valid, err := validateEmail(email)
|
||||
if !valid {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||
if err != nil {
|
||||
@@ -725,10 +717,14 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
if oldClients[clientIndex].Enable {
|
||||
err1 := s.xrayApi.RemoveUser(oldInbound.Tag, oldEmail)
|
||||
if err1 == nil {
|
||||
logger.Debug("Old client deleted by api:", clients[0].Email)
|
||||
logger.Debug("Old client deleted by api:", oldEmail)
|
||||
} else {
|
||||
logger.Debug("Error in deleting client by api:", err1)
|
||||
needRestart = true
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", oldEmail)) {
|
||||
logger.Debug("User is already deleted. Nothing to do more...")
|
||||
} else {
|
||||
logger.Debug("Error in deleting client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if clients[0].Enable {
|
||||
@@ -1088,8 +1084,16 @@ func (s *InboundService) disableInvalidClients(tx *gorm.DB) (bool, int64, error)
|
||||
if err1 == nil {
|
||||
logger.Debug("Client disabled by api:", result.Email)
|
||||
} else {
|
||||
logger.Debug("Error in disabling client by api:", err1)
|
||||
needRestart = true
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", result.Email)) {
|
||||
logger.Debug("User is already disabled. Nothing to do more...")
|
||||
} else {
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", result.Email)) {
|
||||
logger.Debug("User is already disabled. Nothing to do more...")
|
||||
} else {
|
||||
logger.Debug("Error in disabling client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s.xrayApi.Close()
|
||||
@@ -1574,7 +1578,7 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, e
|
||||
return false, err
|
||||
}
|
||||
for _, client := range clients {
|
||||
if client.Email == clientEmail {
|
||||
if client.Email == clientEmail && client.Enable {
|
||||
s.xrayApi.Init(p.GetAPIPort())
|
||||
cipher := ""
|
||||
if string(inbound.Protocol) == "shadowsocks" {
|
||||
@@ -2021,20 +2025,3 @@ func (s *InboundService) MigrateDB() {
|
||||
func (s *InboundService) GetOnlineClients() []string {
|
||||
return p.GetOnlineClients()
|
||||
}
|
||||
|
||||
func validateEmail(email string) (bool, error) {
|
||||
if strings.Contains(email, " ") {
|
||||
return false, errors.New("email contains spaces, please remove them")
|
||||
}
|
||||
|
||||
if email != strings.ToLower(email) {
|
||||
return false, errors.New("email contains uppercase letters, please convert to lowercase")
|
||||
}
|
||||
|
||||
emailPattern := `^[a-z0-9._-]+$`
|
||||
if !regexp.MustCompile(emailPattern).MatchString(email) {
|
||||
return false, errors.New("email contains invalid characters, please use only lowercase letters, digits, dots, dashes, and underscores")
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -248,28 +248,46 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status {
|
||||
}
|
||||
|
||||
func (s *ServerService) GetXrayVersions() ([]string, error) {
|
||||
url := "https://api.github.com/repos/XTLS/Xray-core/releases"
|
||||
resp, err := http.Get(url)
|
||||
const (
|
||||
XrayURL = "https://api.github.com/repos/XTLS/Xray-core/releases"
|
||||
bufferSize = 8192
|
||||
)
|
||||
|
||||
resp, err := http.Get(XrayURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
|
||||
buffer := bytes.NewBuffer(make([]byte, bufferSize))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
if _, err := buffer.ReadFrom(resp.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
releases := make([]Release, 0)
|
||||
err = json.Unmarshal(buffer.Bytes(), &releases)
|
||||
if err != nil {
|
||||
var releases []Release
|
||||
if err := json.Unmarshal(buffer.Bytes(), &releases); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var versions []string
|
||||
for _, release := range releases {
|
||||
if release.TagName >= "v1.7.5" {
|
||||
tagVersion := strings.TrimPrefix(release.TagName, "v")
|
||||
tagParts := strings.Split(tagVersion, ".")
|
||||
if len(tagParts) != 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
major, err1 := strconv.Atoi(tagParts[0])
|
||||
minor, err2 := strconv.Atoi(tagParts[1])
|
||||
patch, err3 := strconv.Atoi(tagParts[2])
|
||||
if err1 != nil || err2 != nil || err3 != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if (major == 1 && minor == 8 && patch == 24) ||
|
||||
(major == 24 && ((minor > 11) || (minor == 11 && patch >= 11))) ||
|
||||
(major > 24) {
|
||||
versions = append(versions, release.TagName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ var defaultValueMap = map[string]string{
|
||||
"webKeyFile": "",
|
||||
"secret": random.Seq(32),
|
||||
"webBasePath": "/",
|
||||
"sessionMaxAge": "0",
|
||||
"sessionMaxAge": "60",
|
||||
"pageSize": "50",
|
||||
"expireDiff": "0",
|
||||
"trafficDiff": "0",
|
||||
@@ -41,6 +41,7 @@ var defaultValueMap = map[string]string{
|
||||
"tgBotEnable": "false",
|
||||
"tgBotToken": "",
|
||||
"tgBotProxy": "",
|
||||
"tgBotAPIServer": "",
|
||||
"tgBotChatId": "",
|
||||
"tgRunTime": "@daily",
|
||||
"tgBotBackup": "false",
|
||||
@@ -62,7 +63,7 @@ var defaultValueMap = map[string]string{
|
||||
"subJsonPath": "/json/",
|
||||
"subJsonURI": "",
|
||||
"subJsonFragment": "",
|
||||
"subJsonNoise": "",
|
||||
"subJsonNoises": "",
|
||||
"subJsonMux": "",
|
||||
"subJsonRules": "",
|
||||
"datepicker": "gregorian",
|
||||
@@ -242,6 +243,10 @@ func (s *SettingService) GetListen() (string, error) {
|
||||
return s.getString("webListen")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetListen(ip string) error {
|
||||
return s.setString("webListen", ip)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetWebDomain() (string, error) {
|
||||
return s.getString("webDomain")
|
||||
}
|
||||
@@ -262,6 +267,14 @@ func (s *SettingService) SetTgBotProxy(token string) error {
|
||||
return s.setString("tgBotProxy", token)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTgBotAPIServer() (string, error) {
|
||||
return s.getString("tgBotAPIServer")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetTgBotAPIServer(token string) error {
|
||||
return s.setString("tgBotAPIServer", token)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTgBotChatId() (string, error) {
|
||||
return s.getString("tgBotChatId")
|
||||
}
|
||||
@@ -459,8 +472,8 @@ func (s *SettingService) GetSubJsonFragment() (string, error) {
|
||||
return s.getString("subJsonFragment")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSubJsonNoise() (string, error) {
|
||||
return s.getString("subJsonNoise")
|
||||
func (s *SettingService) GetSubJsonNoises() (string, error) {
|
||||
return s.getString("subJsonNoises")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSubJsonMux() (string, error) {
|
||||
|
||||
@@ -108,8 +108,14 @@ func (t *Tgbot) Start(i18nFS embed.FS) error {
|
||||
logger.Warning("Failed to get Telegram bot proxy URL:", err)
|
||||
}
|
||||
|
||||
// Get Telegram bot API server URL
|
||||
tgBotAPIServer, err := t.settingService.GetTgBotAPIServer()
|
||||
if err != nil {
|
||||
logger.Warning("Failed to get Telegram bot API server URL:", err)
|
||||
}
|
||||
|
||||
// Create new Telegram bot instance
|
||||
bot, err = t.NewBot(tgBotToken, tgBotProxy)
|
||||
bot, err = t.NewBot(tgBotToken, tgBotProxy, tgBotAPIServer)
|
||||
if err != nil {
|
||||
logger.Error("Failed to initialize Telegram bot API:", err)
|
||||
return err
|
||||
@@ -125,26 +131,40 @@ func (t *Tgbot) Start(i18nFS embed.FS) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tgbot) NewBot(token string, proxyUrl string) (*telego.Bot, error) {
|
||||
if proxyUrl == "" {
|
||||
// No proxy URL provided, use default instance
|
||||
func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*telego.Bot, error) {
|
||||
if proxyUrl == "" && apiServerUrl == "" {
|
||||
return telego.NewBot(token)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(proxyUrl, "socks5://") {
|
||||
logger.Warning("Invalid socks5 URL, starting with default")
|
||||
if proxyUrl != "" {
|
||||
if !strings.HasPrefix(proxyUrl, "socks5://") {
|
||||
logger.Warning("Invalid socks5 URL, using default")
|
||||
return telego.NewBot(token)
|
||||
}
|
||||
|
||||
_, err := url.Parse(proxyUrl)
|
||||
if err != nil {
|
||||
logger.Warningf("Can't parse proxy URL, using default instance for tgbot: %v", err)
|
||||
return telego.NewBot(token)
|
||||
}
|
||||
|
||||
return telego.NewBot(token, telego.WithFastHTTPClient(&fasthttp.Client{
|
||||
Dial: fasthttpproxy.FasthttpSocksDialer(proxyUrl),
|
||||
}))
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(apiServerUrl, "http") {
|
||||
logger.Warning("Invalid http(s) URL, using default")
|
||||
return telego.NewBot(token)
|
||||
}
|
||||
|
||||
_, err := url.Parse(proxyUrl)
|
||||
_, err := url.Parse(apiServerUrl)
|
||||
if err != nil {
|
||||
logger.Warning("Can't parse proxy URL, using default instance for tgbot:", err)
|
||||
logger.Warningf("Can't parse API server URL, using default instance for tgbot: %v", err)
|
||||
return telego.NewBot(token)
|
||||
}
|
||||
|
||||
return telego.NewBot(token, telego.WithFastHTTPClient(&fasthttp.Client{
|
||||
Dial: fasthttpproxy.FasthttpSocksDialer(proxyUrl),
|
||||
}))
|
||||
return telego.NewBot(token, telego.WithAPIServer(apiServerUrl))
|
||||
}
|
||||
|
||||
func (t *Tgbot) IsRunning() bool {
|
||||
@@ -243,7 +263,12 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
|
||||
|
||||
command, _, commandArgs := tu.ParseCommand(message.Text)
|
||||
|
||||
// Extract the command from the Message.
|
||||
// Helper function to handle unknown commands.
|
||||
handleUnknownCommand := func() {
|
||||
msg += t.I18nBot("tgbot.commands.unknown")
|
||||
}
|
||||
|
||||
// Handle the command.
|
||||
switch command {
|
||||
case "help":
|
||||
msg += t.I18nBot("tgbot.commands.help")
|
||||
@@ -266,9 +291,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
|
||||
if isAdmin {
|
||||
t.searchClient(chatId, commandArgs[0])
|
||||
} else {
|
||||
// Convert message.From.ID to int64
|
||||
fromID := int64(message.From.ID)
|
||||
t.getClientUsage(chatId, fromID, commandArgs[0])
|
||||
t.getClientUsage(chatId, int64(message.From.ID), commandArgs[0])
|
||||
}
|
||||
} else {
|
||||
msg += t.I18nBot("tgbot.commands.usage")
|
||||
@@ -278,19 +301,46 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
|
||||
if isAdmin && len(commandArgs) > 0 {
|
||||
t.searchInbound(chatId, commandArgs[0])
|
||||
} else {
|
||||
msg += t.I18nBot("tgbot.commands.unknown")
|
||||
handleUnknownCommand()
|
||||
}
|
||||
case "restart":
|
||||
onlyMessage = true
|
||||
if isAdmin {
|
||||
if len(commandArgs) == 0 {
|
||||
msg += t.I18nBot("tgbot.commands.restartUsage")
|
||||
} else if strings.ToLower(commandArgs[0]) == "force" {
|
||||
if t.xrayService.IsXrayRunning() {
|
||||
err := t.xrayService.RestartXray(true)
|
||||
if err != nil {
|
||||
msg += t.I18nBot("tgbot.commands.restartFailed", "Error=="+err.Error())
|
||||
} else {
|
||||
msg += t.I18nBot("tgbot.commands.restartSuccess")
|
||||
}
|
||||
} else {
|
||||
msg += t.I18nBot("tgbot.commands.xrayNotRunning")
|
||||
}
|
||||
} else {
|
||||
handleUnknownCommand()
|
||||
msg += t.I18nBot("tgbot.commands.restartUsage")
|
||||
}
|
||||
} else {
|
||||
handleUnknownCommand()
|
||||
}
|
||||
default:
|
||||
msg += t.I18nBot("tgbot.commands.unknown")
|
||||
handleUnknownCommand()
|
||||
}
|
||||
|
||||
if msg != "" {
|
||||
if onlyMessage {
|
||||
t.SendMsgToTgbot(chatId, msg)
|
||||
return
|
||||
} else {
|
||||
t.SendAnswer(chatId, msg, isAdmin)
|
||||
}
|
||||
t.sendResponse(chatId, msg, onlyMessage, isAdmin)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to send the message based on onlyMessage flag.
|
||||
func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) {
|
||||
if onlyMessage {
|
||||
t.SendMsgToTgbot(chatId, msg)
|
||||
} else {
|
||||
t.SendAnswer(chatId, msg, isAdmin)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,6 +922,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
|
||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.onlines")).WithCallbackData(t.encodeQuery("onlines")),
|
||||
tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.allClients")).WithCallbackData(t.encodeQuery("get_inbounds")),
|
||||
),
|
||||
// TODOOOOOOOOOOOOOO: Add restart button here.
|
||||
)
|
||||
numericKeyboardClient := tu.InlineKeyboard(
|
||||
tu.InlineKeyboardRow(
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
"domainName" = "Domain Name"
|
||||
"monitor" = "Listen IP"
|
||||
"certificate" = "Digital Certificate"
|
||||
"fail" = " Failed"
|
||||
"success" = " Successfully"
|
||||
"fail" = "Failed"
|
||||
"success" = "Successfully"
|
||||
"getVersion" = "Get Version"
|
||||
"install" = "Install"
|
||||
"clients" = "Clients"
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Destination Port"
|
||||
"targetAddress" = "Target Address"
|
||||
"monitorDesc" = "Leave blank to listen on all IPs"
|
||||
"meansNoLimit" = " = Unlimited. (unit: GB)"
|
||||
"meansNoLimit" = "= Unlimited. (unit: GB)"
|
||||
"totalFlow" = "Total Flow"
|
||||
"leaveBlankToNeverExpire" = "Leave blank to never expire"
|
||||
"noRecommendKeepDefault" = "It is recommended to keep the default"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "The IPs history log. (to enable inbound after disabling, clear the log)"
|
||||
"IPLimitlogclear" = "Clear The Log"
|
||||
"setDefaultCert" = "Set Cert from Panel"
|
||||
"xtlsDesc" = "Xray must be v1.7.5"
|
||||
"realityDesc" = "Xray must be v1.8.0+"
|
||||
"telegramDesc" = "Please provide Telegram Chat ID. (use '/id' command in the bot) or (@userinfobot)"
|
||||
"subscriptionDesc" = "To find your subscription URL, navigate to the 'Details'. Additionally, you can use the same name for several clients."
|
||||
"info" = "Info"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "The Telegram bot token obtained from '@BotFather'."
|
||||
"telegramProxy" = "SOCKS Proxy"
|
||||
"telegramProxyDesc" = "Enables SOCKS5 proxy for connecting to Telegram. (adjust settings as per guide)"
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
"telegramAPIServerDesc" = "The Telegram API server to use. Leave blank to use the default server."
|
||||
"telegramChatId" = "Admin Chat ID"
|
||||
"telegramChatIdDesc" = "The Telegram Admin Chat ID(s). (comma-separated)(get it here @userinfobot) or (use '/id' command in the bot)"
|
||||
"telegramNotifyTime" = "Notification Time"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Fragmentation"
|
||||
"fragmentDesc" = "Enable fragmentation for TLS hello packet."
|
||||
"fragmentSett" = "Fragmentation Settings"
|
||||
"noiseDesc" = "Enable Noise."
|
||||
"noiseSett" = "Noise Settings"
|
||||
"noisesDesc" = "Enable Noises."
|
||||
"noisesSett" = "Noises Settings"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Transmit multiple independent data streams within an established data stream."
|
||||
"muxSett" = "Mux Settings"
|
||||
"direct" = "Direct Connection"
|
||||
"directDesc" = "Directly establishes connections with domains or IP ranges of a specific country."
|
||||
"directSett" = "Direct Connection Options"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray Configs"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Logs may affect your server's efficiency. It is recommended to enable it wisely only in case of your needs"
|
||||
"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" = "A direct connection ensures that specific traffic is not routed through another server."
|
||||
"ipv4Configs" = "IPv4 Routing"
|
||||
"ipv4ConfigsDesc" = "These options will route traffic based on a specific destination via IPv4."
|
||||
"warpConfigs" = "WARP Routing"
|
||||
"warpConfigsDesc" = "These options will route traffic based on a specific destination via WARP."
|
||||
"basicRouting" = "Basic Routing"
|
||||
"blockConnectionsConfigsDesc" = "These options will block traffic based on the specific requested country."
|
||||
"directConnectionsConfigsDesc" = "A direct connection ensures that specific traffic is not routed through another server."
|
||||
"blockips" = "Block IPs"
|
||||
"blockdomains" = "Block Domains"
|
||||
"directips" = "Direct IPs"
|
||||
"directdomains" = "Direct Domains"
|
||||
"ipv4Routing" = "IPv4 Routing"
|
||||
"ipv4RoutingDesc" = "These options will route traffic based on a specific destination via IPv4."
|
||||
"warpRouting" = "WARP Routing"
|
||||
"warpRoutingDesc" = "These options will route traffic based on a specific destination via WARP."
|
||||
"Template" = "Advanced Xray Configuration Template"
|
||||
"TemplateDesc" = "The final Xray config file will be generated based on this template."
|
||||
"FreedomStrategy" = "Freedom Protocol Strategy"
|
||||
@@ -346,68 +349,8 @@
|
||||
"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" = "Blocks advertising websites."
|
||||
"Family" = "Family Protection"
|
||||
"FamilyDesc" = "Blocks adult content, and malware websites."
|
||||
"Security" = "Security Shield"
|
||||
"SecurityDesc" = "Blocks malware, phishing, and cryptominers websites."
|
||||
"Speedtest" = "Block Speedtest"
|
||||
"SpeedtestDesc" = "Blocks establishing connectins to speedtest 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."
|
||||
"VNIp" = "Block Connection to Vietnam IPs"
|
||||
"VNIpDesc" = "Blocks establishing connections to Vietnam IP ranges."
|
||||
"VNDomain" = "Block Connection to Vietnam Domains"
|
||||
"VNDomainDesc" = "Blocks establishing connections to Vietnam 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."
|
||||
"DirectVNIp" = "Direct Connection to Vietnam IPs"
|
||||
"DirectVNIpDesc" = "Directly establishes connections to Vietnam IP ranges."
|
||||
"DirectVNDomain" = "Direct Connection to Vietnam Domains"
|
||||
"DirectVNDomainDesc" = "Directly establishes connections to Vietnam domains."
|
||||
"GoogleIPv4" = "Google"
|
||||
"GoogleIPv4Desc" = "Routes traffic to Google via IPv4."
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "Routes traffic to Netflix via IPv4."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Add routing for Google via WARP."
|
||||
"OpenAIWARP" = "ChatGPT"
|
||||
"OpenAIWARPDesc" = "Routes traffic to ChatGPT via WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Routes traffic to Netflix via WARP."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Routes traffic to Meta (Instagram, Facebook, WhatsApp, Threads,...) via WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Routes traffic to Apple via WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Routes traffic to Reddit via WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Routes traffic to Spotify via WARP."
|
||||
"IRWARP" = "Iran domains"
|
||||
"IRWARPDesc" = "Routes traffic to Iran domains via WARP."
|
||||
"Inbounds" = "Inbounds"
|
||||
"InboundsDesc" = "Accepting the specific clients."
|
||||
"Outbounds" = "Outbounds"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "The file path for the access log. The special value 'none' disabled access logs"
|
||||
"errorLog" = "Error Log"
|
||||
"errorLogDesc" = "The file path for the error log. The special value 'none' disabled error logs"
|
||||
"dnsLog" = "DNS Log"
|
||||
"dnsLogDesc" = "Whether to enable DNS query logs"
|
||||
"maskAddress" = "Mask Address"
|
||||
"maskAddressDesc" = "IP address mask, when enabled, will automatically replace the IP address that appears in the log."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "First"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Add Server"
|
||||
"edit" = "Edit Server"
|
||||
"domains" = "Domains"
|
||||
"expectIPs" = "Expect IPs"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Add Fake DNS"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ Bot is OK!"
|
||||
"usage" = "❗ Please provide a text to search!"
|
||||
"getID" = "🆔 Your ID: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "To search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "To restart Xray Core:\r\n<code>/restart force</code>\r\n\r\nTo search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "To search for statistics, use the following command:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ Operation successful!"
|
||||
"restartFailed" = "❗ Error in operation.\r\n\r\n<code>Error: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core is not running."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%"
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Puerto de Destino"
|
||||
"targetAddress" = "Dirección de Destino"
|
||||
"monitorDesc" = "Dejar en blanco por defecto"
|
||||
"meansNoLimit" = " = illimitata. (unidad: GB)"
|
||||
"meansNoLimit" = "= illimitata. (unidad: GB)"
|
||||
"totalFlow" = "Flujo Total"
|
||||
"leaveBlankToNeverExpire" = "Dejar en Blanco para Nunca Expirar"
|
||||
"noRecommendKeepDefault" = "No hay requisitos especiales para mantener la configuración predeterminada"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "Registro de historial de IPs (antes de habilitar la entrada después de que haya sido desactivada por el límite de IP, debes borrar el registro)."
|
||||
"IPLimitlogclear" = "Limpiar el Registro"
|
||||
"setDefaultCert" = "Establecer certificado desde el panel"
|
||||
"xtlsDesc" = "La versión del núcleo de Xray debe ser 1.7.5"
|
||||
"realityDesc" = "La versión del núcleo de Xray debe ser 1.8.0 o superior."
|
||||
"telegramDesc" = "Por favor, proporciona el ID de Chat de Telegram. (usa el comando '/id' en el bot) o (@userinfobot)"
|
||||
"subscriptionDesc" = "Puedes encontrar tu enlace de suscripción en Detalles, también puedes usar el mismo nombre para varias configuraciones."
|
||||
"info" = "Info"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "Debe obtener el token del administrador de bots de Telegram @botfather."
|
||||
"telegramProxy" = "Socks5 Proxy"
|
||||
"telegramProxyDesc" = "Si necesita el proxy Socks5 para conectarse a Telegram. Ajuste su configuración según la guía."
|
||||
"telegramAPIServer" = "API Server de Telegram"
|
||||
"telegramAPIServerDesc" = "El servidor API de Telegram a utilizar. Déjelo en blanco para utilizar el servidor predeterminado."
|
||||
"telegramChatId" = "IDs de Chat de Telegram para Administradores"
|
||||
"telegramChatIdDesc" = "IDs de Chat múltiples separados por comas. Use @userinfobot o use el comando '/id' en el bot para obtener sus IDs de Chat."
|
||||
"telegramNotifyTime" = "Hora de Notificación del Bot de Telegram"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Fragmentación"
|
||||
"fragmentDesc" = "Habilitar la fragmentación para el paquete de saludo de TLS"
|
||||
"fragmentSett" = "Configuración de Fragmentación"
|
||||
"noiseDesc" = "Activar Noise."
|
||||
"noiseSett" = "Configuración de Noise"
|
||||
"noisesDesc" = "Activar Noises."
|
||||
"noisesSett" = "Configuración de Noises"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Transmite múltiples flujos de datos independientes dentro de un flujo de datos establecido."
|
||||
"muxSett" = "Configuración Mux"
|
||||
"direct" = "Conexión Directa"
|
||||
"directDesc" = "Establece conexiones directas con dominios o rangos de IP de un país específico."
|
||||
"directSett" = "Opciones de Conexión Directa"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray Configuración"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Los registros pueden afectar la eficiencia de su servidor. Se recomienda habilitarlos sabiamente solo en caso de sus necesidades."
|
||||
"blockConfigs" = "Configuraciones de Bloqueo"
|
||||
"blockConfigsDesc" = "Estas opciones evitarán que los usuarios se conecten a protocolos y sitios web específicos."
|
||||
"blockCountryConfigs" = "Configuraciones de Bloqueo por País"
|
||||
"blockCountryConfigsDesc" = "Estas opciones evitarán que los usuarios se conecten a dominios de países específicos."
|
||||
"directCountryConfigs" = "Configuraciones de Conexión Directa por País"
|
||||
"directCountryConfigsDesc" = "Una conexión directa asegura que el tráfico específico no se enrutará a través de otro servidor."
|
||||
"ipv4Configs" = "Configuraciones IPv4"
|
||||
"ipv4ConfigsDesc" = "Estas opciones solo enrutarán a los dominios objetivo a través de IPv4."
|
||||
"warpConfigs" = "Configuraciones de WARP"
|
||||
"warpConfigsDesc" = "Precaución: Antes de usar estas opciones, instale WARP en modo de proxy socks5 en su servidor siguiendo los pasos en el GitHub del panel. WARP enrutará el tráfico a los sitios web a través de los servidores de Cloudflare."
|
||||
"basicRouting" = "Enrutamiento Básico"
|
||||
"blockConnectionsConfigsDesc" = "Estas opciones bloquearán el tráfico según el país solicitado específico."
|
||||
"directConnectionsConfigsDesc" = "Una conexión directa asegura que el tráfico específico no sea enrutado a través de otro servidor."
|
||||
"blockips" = "Bloquear IPs"
|
||||
"blockdomains" = "Bloquear Dominios"
|
||||
"directips" = "IPs Directas"
|
||||
"directdomains" = "Dominios Directos"
|
||||
"ipv4Routing" = "Enrutamiento IPv4"
|
||||
"ipv4RoutingDesc" = "Estas opciones solo enrutarán a los dominios objetivo a través de IPv4."
|
||||
"warpRouting" = "Enrutamiento WARP"
|
||||
"warpRoutingDesc" = "Precaución: Antes de usar estas opciones, instale WARP en modo de proxy socks5 en su servidor siguiendo los pasos en el GitHub del panel. WARP enrutará el tráfico a los sitios web a través de los servidores de Cloudflare."
|
||||
"Template" = "Plantilla de Configuración de Xray"
|
||||
"TemplateDesc" = "Genera el archivo de configuración final de Xray basado en esta plantilla."
|
||||
"FreedomStrategy" = "Configurar Estrategia para el Protocolo Freedom"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "Establece la estrategia general de enrutamiento para la resolución de DNS."
|
||||
"Torrent" = "Prohibir Uso de BitTorrent"
|
||||
"TorrentDesc" = "Cambia la plantilla de configuración para evitar el uso de BitTorrent por parte de los usuarios."
|
||||
"PrivateIp" = "Prohibir Conexiones a Rangos de IP Privadas"
|
||||
"PrivateIpDesc" = "Cambia la plantilla de configuración para evitar la conexión a rangos de IP privadas."
|
||||
"Ads" = "Bloquear Anuncios"
|
||||
"AdsDesc" = "Cambia la plantilla de configuración para bloquear anuncios."
|
||||
"Family" = "Bloquee malware y contenido para adultos"
|
||||
"FamilyDesc" = "Resolutores de DNS de Cloudflare para bloquear malware y contenido para adultos para protección familiar."
|
||||
"Security" = "Escudo de Seguridad"
|
||||
"SecurityDesc" = "Cambiar la plantilla de configuración para la protección de seguridad."
|
||||
"Speedtest" = "Bloquear Sitios Web de Pruebas de Velocidad"
|
||||
"SpeedtestDesc" = "Cambia la plantilla de configuración para evitar la conexión a sitios web de pruebas de velocidad."
|
||||
"IRIp" = "Desactivar Conexión a Rangos de IP de Irán"
|
||||
"IRIpDesc" = "Cambia la plantilla de configuración para evitar la conexión a rangos de IP de Irán."
|
||||
"IRDomain" = "Desactivar Conexión a Dominios de Irán"
|
||||
"IRDomainDesc" = "Cambia la plantilla de configuración para evitar la conexión a dominios de Irán."
|
||||
"ChinaIp" = "Desactivar Conexión a Rangos de IP de China"
|
||||
"ChinaIpDesc" = "Cambia la plantilla de configuración para evitar la conexión a rangos de IP de China."
|
||||
"ChinaDomain" = "Desactivar Conexión a Dominios de China"
|
||||
"ChinaDomainDesc" = "Cambia la plantilla de configuración para evitar la conexión a dominios de China."
|
||||
"RussiaIp" = "Desactivar Conexión a Rangos de IP de Rusia"
|
||||
"RussiaIpDesc" = "Cambia la plantilla de configuración para evitar la conexión a rangos de IP de Rusia."
|
||||
"RussiaDomain" = "Desactivar Conexión a Dominios de Rusia"
|
||||
"RussiaDomainDesc" = "Cambia la plantilla de configuración para evitar la conexión a dominios de Rusia."
|
||||
"VNIp" = "Deshabilitar la conexión a las IP de Vietnam"
|
||||
"VNIpDesc" = "Cambie la plantilla de configuración para evitar conectarse a rangos de IP de Vietnam."
|
||||
"VNDomain" = "Deshabilitar la conexión a dominios de Vietnam"
|
||||
"VNDomainDesc" = "Cambie la plantilla de configuración para evitar conectarse a dominios de Vietnam."
|
||||
"DirectIRIp" = "Conexión Directa a Rangos de IP de Irán"
|
||||
"DirectIRIpDesc" = "Cambia la plantilla de configuración para conectarse directamente a rangos de IP de Irán."
|
||||
"DirectIRDomain" = "Conexión Directa a Dominios de Irán"
|
||||
"DirectIRDomainDesc" = "Cambia la plantilla de configuración para conectarse directamente a dominios de Irán."
|
||||
"DirectChinaIp" = "Conexión Directa a Rangos de IP de China"
|
||||
"DirectChinaIpDesc" = "Cambia la plantilla de configuración para conectarse directamente a rangos de IP de China."
|
||||
"DirectChinaDomain" = "Conexión Directa a Dominios de China"
|
||||
"DirectChinaDomainDesc" = "Cambia la plantilla de configuración para conectarse directamente a dominios de China."
|
||||
"DirectRussiaIp" = "Conexión Directa a Rangos de IP de Rusia"
|
||||
"DirectRussiaIpDesc" = "Cambia la plantilla de configuración para conectarse directamente a rangos de IP de Rusia."
|
||||
"DirectRussiaDomain" = "Conexión Directa a Dominios de Rusia"
|
||||
"DirectRussiaDomainDesc" = "Cambia la plantilla de configuración para conectarse directamente a dominios de Rusia."
|
||||
"DirectVNIp" = "Conexión directa a IP de Vietnam"
|
||||
"DirectVNIpDesc" = "Cambie la plantilla de configuración para la conexión directa a rangos de IP de Vietnam."
|
||||
"DirectVNDomain" = "Conexión directa a dominios de Vietnam"
|
||||
"DirectVNDomainDesc" = "Cambie la plantilla de configuración para la conexión directa a dominios de Vietnam."
|
||||
"GoogleIPv4" = "Usar IPv4 para Google"
|
||||
"GoogleIPv4Desc" = "Agregar enrutamiento para que Google se conecte con IPv4."
|
||||
"NetflixIPv4" = "Usar IPv4 para Netflix"
|
||||
"NetflixIPv4Desc" = "Agregar enrutamiento para que Netflix se conecte con IPv4."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Agrega enrutamiento para Google a través de WARP."
|
||||
"OpenAIWARP" = "ChatGPT"
|
||||
"OpenAIWARPDesc" = "Enruta el tráfico a ChatGPT a través de WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Enruta el tráfico a Netflix a través de WARP."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Enruta el tráfico a Meta (Instagram, Facebook, WhatsApp, Threads, etc.) a través de WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Enruta el tráfico a Apple a través de WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Enruta el tráfico a Reddit a través de WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Enruta el tráfico a Spotify a través de WARP."
|
||||
"IRWARP" = "Rutear dominios de Irán a través de WARP."
|
||||
"IRWARPDesc" = "Agregar enrutamiento para dominios de Irán a través de WARP."
|
||||
"Inbounds" = "Entrante"
|
||||
"InboundsDesc" = "Cambia la plantilla de configuración para aceptar clientes específicos."
|
||||
"Outbounds" = "Salidas"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "La ruta del archivo para el registro de acceso. El valor especial 'ninguno' deshabilita los registros de acceso"
|
||||
"errorLog" = "Registro de Errores"
|
||||
"errorLogDesc" = "La ruta del archivo para el registro de errores. El valor especial 'none' desactiva los registros de errores."
|
||||
"dnsLog" = "Registro DNS"
|
||||
"dnsLogDesc" = "Si habilitar los registros de consulta DNS"
|
||||
"maskAddress" = "Enmascarar Dirección"
|
||||
"maskAddressDesc" = "Máscara de dirección IP, cuando se habilita, reemplazará automáticamente la dirección IP que aparece en el registro."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "Primero"
|
||||
@@ -477,11 +424,14 @@
|
||||
[pages.xray.dns]
|
||||
"enable" = "Habilitar DNS"
|
||||
"enableDesc" = "Habilitar servidor DNS incorporado"
|
||||
"tag" = "Etiqueta de Entrada DNS"
|
||||
"tagDesc" = "Esta etiqueta estará disponible como una etiqueta de entrada en las reglas de enrutamiento."
|
||||
"strategy" = "Estrategia de Consulta"
|
||||
"strategyDesc" = "Estrategia general para resolver nombres de dominio"
|
||||
"add" = "Agregar Servidor"
|
||||
"edit" = "Editar Servidor"
|
||||
"domains" = "Dominios"
|
||||
"expectIPs" = "IPs esperadas"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Agregar DNS Falso"
|
||||
@@ -533,8 +483,12 @@
|
||||
"status" = "✅ ¡El bot está bien!"
|
||||
"usage" = "❗ ¡Por favor proporciona un texto para buscar!"
|
||||
"getID" = "🆔 Tu ID: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Para buscar un correo electrónico de cliente:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n<code>/inbound [Observación]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "Para reiniciar Xray Core:\r\n<code>/restart force</code>\r\n\r\nPara buscar un correo electrónico de cliente:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n<code>/inbound [Observación]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "Para buscar estadísticas, utiliza el siguiente comando:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ ¡Operación exitosa!"
|
||||
"restartFailed" = "❗ Error en la operación.\r\n\r\n<code>Error: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core no está en ejecución."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 El uso de CPU {{ .Percent }}% es mayor que el umbral {{ .Threshold }}%"
|
||||
@@ -591,7 +545,7 @@
|
||||
"confirmResetTraffic" = "✅ ¿Confirmar Reinicio de Tráfico?"
|
||||
"confirmClearIps" = "✅ ¿Confirmar Limpiar IPs?"
|
||||
"confirmRemoveTGUser" = "✅ ¿Confirmar Eliminar Usuario de Telegram?"
|
||||
"confirmToggle" = " ✅ ¿Confirmar habilitar/deshabilitar usuario?"
|
||||
"confirmToggle" = "✅ ¿Confirmar habilitar/deshabilitar usuario?"
|
||||
"dbBackup" = "Obtener Copia de Seguridad de BD"
|
||||
"serverUsage" = "Uso del Servidor"
|
||||
"getInbounds" = "Obtener Entradas"
|
||||
@@ -638,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }} : Deshabilitado exitosamente."
|
||||
"askToAddUserId" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su ChatID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu ChatID de usuario: <code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "Elige un Cliente para Inbound {{ .Inbound }}"
|
||||
"chooseInbound" = "Elige un Inbound"
|
||||
"chooseInbound" = "Elige un Inbound"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"monitor" = "آیپی اتصال"
|
||||
"certificate" = "گواهی دیجیتال"
|
||||
"fail" = "ناموفق"
|
||||
"success" = " موفق"
|
||||
"success" = "موفق"
|
||||
"getVersion" = "دریافت نسخه"
|
||||
"install" = "نصب"
|
||||
"clients" = "کاربران"
|
||||
@@ -109,7 +109,7 @@
|
||||
"backup" = "پشتیبانگیری"
|
||||
"backupTitle" = "پشتیبانگیری دیتابیس"
|
||||
"backupDescription" = "توصیهمیشود قبلاز واردکردن یک دیتابیس جدید، نسخه پشتیبان تهیه کنید"
|
||||
"exportDatabase" = " پشتیبانگیری"
|
||||
"exportDatabase" = "پشتیبانگیری"
|
||||
"importDatabase" = "بازگرداندن"
|
||||
|
||||
[pages.inbounds]
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "گزارش تاریخچه آیپی. برای فعال کردن ورودی پس از غیرفعال شدن، گزارش را پاک کنید"
|
||||
"IPLimitlogclear" = "پاک کردن گزارشها"
|
||||
"setDefaultCert" = "استفاده از گواهی پنل"
|
||||
"xtlsDesc" = "ایکسری باید 1.7.5 باشد"
|
||||
"realityDesc" = "ایکسری باید +1.8.0 باشد"
|
||||
"telegramDesc" = "لطفا شناسه گفتگوی تلگرام را وارد کنید. (از دستور '/id' در ربات استفاده کنید) یا (@userinfobot)"
|
||||
"subscriptionDesc" = "شما میتوانید لینک سابسکربپشن خودرا در 'جزئیات' پیدا کنید، همچنین میتوانید از همین نام برای چندین کاربر استفادهکنید"
|
||||
"info" = "اطلاعات"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "دریافت کنید @botfather توکن را میتوانید از"
|
||||
"telegramProxy" = "SOCKS پراکسی"
|
||||
"telegramProxyDesc" = "را برای اتصال به تلگرام فعال می کند SOCKS5 پراکسی"
|
||||
"telegramAPIServer" = "سرور API تلگرام"
|
||||
"telegramAPIServerDesc" = "API سرور تلگرام برای اتصال را تغییر میدهد. برای استفاده از سرور پیش فرض خالی بگذارید"
|
||||
"telegramChatId" = "آیدی چت مدیر"
|
||||
"telegramChatIdDesc" = "دریافت کنید ('/id'یا (دستور (@userinfobot) آیدی(های) چت تلگرام مدیر، از"
|
||||
"telegramNotifyTime" = "زمان نوتیفیکیشن"
|
||||
@@ -285,7 +285,7 @@
|
||||
"timeZoneDesc" = "وظایف برنامه ریزی شده بر اساس این منطقهزمانی اجرا میشود"
|
||||
"subSettings" = "سابسکریپشن"
|
||||
"subEnable" = "فعالسازی سرویس سابسکریپشن"
|
||||
"subEnableDesc" = " سرویس سابسکریپشن را فعالمیکند"
|
||||
"subEnableDesc" = "سرویس سابسکریپشن را فعالمیکند"
|
||||
"subListen" = "آدرس آیپی"
|
||||
"subListenDesc" = "آدرس آیپی برای سرویس سابسکریپشن. برای گوش دادن بهتمام آیپیها خالیبگذارید"
|
||||
"subPort" = "پورت"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "فرگمنت"
|
||||
"fragmentDesc" = "فعال کردن فرگمنت برای بستهی نخست تیالاس"
|
||||
"fragmentSett" = "تنظیمات فرگمنت"
|
||||
"noiseDesc" = "فعال کردن Noise."
|
||||
"noiseSett" = "تنظیمات Noise"
|
||||
"noisesDesc" = "فعال کردن Noises."
|
||||
"noisesSett" = "تنظیمات Noises"
|
||||
"mux" = "ماکس"
|
||||
"muxDesc" = "چندین جریان داده مستقل را در یک جریان داده ثابت منتقل می کند"
|
||||
"muxSett" = "تنظیمات ماکس"
|
||||
"direct" = "اتصال مستقیم"
|
||||
"directDesc" = "به طور مستقیم با دامنه ها یا محدوده آیپی یک کشور خاص ارتباط برقرار می کند"
|
||||
"directSett" = "گزینه های اتصال مستقیم"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "پیکربندی ایکسری"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "گزارشها ممکن است بر کارایی سرور شما تأثیر بگذارد. توصیه می شود فقط در صورت نیاز آن را عاقلانه فعال کنید"
|
||||
"blockConfigs" = "سپر محافظ"
|
||||
"blockConfigsDesc" = "این گزینهها ترافیک را بر اساس پروتکلهای درخواستی خاص، و وب سایتها مسدود میکند"
|
||||
"blockCountryConfigs" = "مسدودسازی کشور"
|
||||
"blockCountryConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستی خاص مسدود میکند"
|
||||
"directCountryConfigs" = "اتصال مستقیم کشور"
|
||||
"directCountryConfigsDesc" = "اتصال مستقیم اطمینان حاصل میکند که ترافیک خاص از طریق یک سرور دیگر هدایت نمیشود."
|
||||
"ipv4Configs" = "IPv4 مسیریابی"
|
||||
"ipv4ConfigsDesc" = "این گزینهها ترافیک را از طریق آیپینسخه4 به مقصد هدایت میکند"
|
||||
"warpConfigs" = "WARP مسیریابی"
|
||||
"warpConfigsDesc" = "طبق راهنما نصب کنید SOCKS5 این گزینهها ترافیک را از طریق وارپ کلادفلر به مقصد هدایت میکند. ابتدا، وارپ را در حالت پراکسی"
|
||||
"basicRouting" = "مسیریابی پایه"
|
||||
"blockConnectionsConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستشده خاص مسدود میکنند."
|
||||
"directConnectionsConfigsDesc" = "یک اتصال مستقیم تضمین میکند که ترافیک خاص از طریق سرور دیگری مسیریابی نشود."
|
||||
"blockips" = "مسدود کردن آیپیها"
|
||||
"blockdomains" = "مسدود کردن دامنهها"
|
||||
"directips" = "آیپیهای مستقیم"
|
||||
"directdomains" = "دامنههای مستقیم"
|
||||
"ipv4Routing" = "IPv4 مسیریابی"
|
||||
"ipv4RoutingDesc" = "این گزینهها ترافیک را از طریق آیپی نسخه4 سرور، به مقصد هدایت میکند"
|
||||
"warpRouting" = "WARP مسیریابی"
|
||||
"warpRoutingDesc" = "این گزینهها ترافیک را از طریق وارپ کلادفلر به مقصد هدایت میکند"
|
||||
"Template" = "پیکربندی پیشرفته الگو ایکسری"
|
||||
"TemplateDesc" = "فایل پیکربندی نهایی ایکسری بر اساس این الگو ایجاد میشود"
|
||||
"FreedomStrategy" = "Freedom استراتژی پروتکل"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "استراتژی کلی مسیریابی برای حل تمام درخواستها را تعیین میکند"
|
||||
"Torrent" = "مسدودسازی پروتکل بیتتورنت"
|
||||
"TorrentDesc" = "پروتکل بیت تورنت را مسدود میکند"
|
||||
"PrivateIp" = "مسدودسازی اتصال آیپیهای خصوصی"
|
||||
"PrivateIpDesc" = "اتصال به آیپیهای رنج خصوصی را مسدود میکند"
|
||||
"Ads" = "مسدودسازی تبلیغات"
|
||||
"AdsDesc" = "وبسایتهای تبلیغاتی را مسدود میکند"
|
||||
"Family" = "محافظت خانواده"
|
||||
"FamilyDesc" = "محتوای مخصوص بزرگسالان، و وبسایتهای ناامن را مسدود میکند"
|
||||
"Security" = "محافظت امنیتی"
|
||||
"SecurityDesc" = "وبسایتهای ناامن، بدافزار، فیشینگ، و کریپتوماینرها را مسدود میکند"
|
||||
"Speedtest" = "مسدودسازی اسپیدتست"
|
||||
"SpeedtestDesc" = "اتصال به وبسایتهای تست سرعت را مسدود میکند"
|
||||
"IRIp" = "مسدودسازی اتصال به آیپیهای ایران"
|
||||
"IRIpDesc" = "اتصال به آیپیهای کشور ایران را مسدود میکند"
|
||||
"IRDomain" = "مسدودسازی اتصال به دامنههای ایران"
|
||||
"IRDomainDesc" = "اتصال به دامنههای کشور ایران را مسدود میکند"
|
||||
"ChinaIp" = "مسدودسازی اتصال به آیپیهای چین"
|
||||
"ChinaIpDesc" = "اتصال به آیپیهای کشور چین را مسدود میکند"
|
||||
"ChinaDomain" = "مسدودسازی اتصال به دامنههای چین"
|
||||
"ChinaDomainDesc" = "اتصال به دامنههای کشور چین را مسدود میکند"
|
||||
"RussiaIp" = "مسدودسازی اتصال به آیپیهای روسیه"
|
||||
"RussiaIpDesc" = "اتصال به آیپیهای کشور روسیه را مسدود میکند"
|
||||
"RussiaDomain" = "مسدودسازی اتصال به دامنههای روسیه"
|
||||
"RussiaDomainDesc" = "اتصال به دامنههای کشور روسیه را مسدود میکند"
|
||||
"VNIp" = "مسدودسازی اتصال به آیپیهای ویتنام"
|
||||
"VNIpDesc" = "اتصال به آیپیهای کشور ویتنام را مسدود میکند"
|
||||
"VNDomain" = "مسدودسازی اتصال به دامنه های ویتنام"
|
||||
"VNDomainDesc" = "اتصال به دامنههای کشور ویتنام را مسدود میکند"
|
||||
"DirectIRIp" = "اتصال مستقیم آیپیهای ایران"
|
||||
"DirectIRIpDesc" = "اتصال مستقیم به آیپیهای کشور ایران"
|
||||
"DirectIRDomain" = "اتصال مستقیم دامنههای ایران"
|
||||
"DirectIRDomainDesc" = "اتصال مستقیم به دامنههای کشور ایران"
|
||||
"DirectChinaIp" = "اتصال مستقیم آیپیهای چین"
|
||||
"DirectChinaIpDesc" = "اتصال مستقیم به آیپیهای کشور چین"
|
||||
"DirectChinaDomain" = "اتصال مستقیم دامنههای چین"
|
||||
"DirectChinaDomainDesc" = "اتصال مستقیم به دامنههای کشور چین"
|
||||
"DirectRussiaIp" = "اتصال مستقیم آیپیهای روسیه"
|
||||
"DirectRussiaIpDesc" = "اتصال مستقیم به آیپیهای کشور روسیه"
|
||||
"DirectRussiaDomain" = "اتصال مستقیم دامنههای روسیه"
|
||||
"DirectRussiaDomainDesc" = "اتصال مستقیم به دامنههای کشور روسیه"
|
||||
"DirectVNIp" = "اتصال مستقیم آیپیهای ویتنام"
|
||||
"DirectVNIpDesc" = "اتصال مستقیم به آیپیهای کشور ویتنام"
|
||||
"DirectVNDomain" = "اتصال مستقیم دامنههای ویتنام"
|
||||
"DirectVNDomainDesc" = "اتصال مستقیم به دامنههای کشور ویتنام"
|
||||
"GoogleIPv4" = "گوگل"
|
||||
"GoogleIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به گوگل هدایت میکند"
|
||||
"NetflixIPv4" = "نتفلیکس"
|
||||
"NetflixIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به نتفلیکس هدایت میکند"
|
||||
"GoogleWARP" = "گوگل"
|
||||
"GoogleWARPDesc" = "ترافیک را از طریق وارپ به گوگل هدایت میکند"
|
||||
"OpenAIWARP" = "چت جیپیتی"
|
||||
"OpenAIWARPDesc" = "ترافیک را از طریق وارپ به چت جیپیتی هدایت میکند"
|
||||
"NetflixWARP" = "نتفلیکس"
|
||||
"NetflixWARPDesc" = "ترافیک را از طریق وارپ به نتفلیکس هدایت میکند"
|
||||
"MetaWARP" = "متا"
|
||||
"MetaWARPDesc" = "ترافیک را از طریق وارپ به متا (اینستاگرام، فیس بوک، واتساپ، تردز و...) هدایت می کند."
|
||||
"AppleWARP" = "اپل"
|
||||
"AppleWARPDesc" = " ترافیک را از طریق وارپ به اپل هدایت میکند"
|
||||
"RedditWARP" = "ردیت"
|
||||
"RedditWARPDesc" = " ترافیک را از طریق وارپ به ردیت هدایت میکند"
|
||||
"SpotifyWARP" = "اسپاتیفای"
|
||||
"SpotifyWARPDesc" = " ترافیک را از طریق وارپ به اسپاتیفای هدایت میکند"
|
||||
"IRWARP" = "دامنههای ایران"
|
||||
"IRWARPDesc" = "ترافیک را از طریق وارپ به دامنههای کشور ایران هدایت میکند"
|
||||
"Inbounds" = "ورودیها"
|
||||
"InboundsDesc" = "پذیرش کلاینت خاص"
|
||||
"Outbounds" = "خروجیها"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "مسیر فایل برای گزارش دسترسی. مقدار ویژه «هیچ» گزارشهای دسترسی را غیرفعال میکند."
|
||||
"errorLog" = "گزارش خطا"
|
||||
"errorLogDesc" = "مسیر فایل برای ورود به سیستم خطا. مقدار ویژه «هیچ» گزارش های خطا را غیرفعال میکند"
|
||||
"dnsLog" = "گزارش DNS"
|
||||
"dnsLogDesc" = "آیا ثبتهای درخواست DNS را فعال کنید"
|
||||
"maskAddress" = "پنهان کردن آدرس"
|
||||
"maskAddressDesc" = "پوشش آدرس IP، هنگامی که فعال میشود، به طور خودکار آدرس IP که در لاگ ظاهر میشود را جایگزین میکند."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "اولین"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "افزودن سرور"
|
||||
"edit" = "ویرایش سرور"
|
||||
"domains" = "دامنهها"
|
||||
"expectIPs" = "آیپیهای مورد انتظار"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "افزودن دیاناس جعلی"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ ربات در حالت عادی است!"
|
||||
"usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!"
|
||||
"getID" = "🆔 شناسه شما: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "برای جستجوی ایمیل مشتری:\r\n<code>/usage [ایمیل]</code>\r\n\r\nبرای جستجوی ورودیها (با آمار مشتری):\r\n<code>/inbound [توضیحات]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "برای راهاندازی مجدد Xray Core:\r\n<code>/restart force</code>\r\n\r\nبرای جستجوی ایمیل مشتری:\r\n<code>/usage [ایمیل]</code>\r\n\r\nبرای جستجوی ورودیها (با آمار مشتری):\r\n<code>/inbound [توضیحات]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "برای جستجوی آمار، از دستور زیر استفاده کنید:\r\n<code>/usage [ایمیل]</code>\r\n\r\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ عملیات با موفقیت انجام شد!"
|
||||
"restartFailed" = "❗ خطا در عملیات.\r\n\r\n<code>خطا: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core در حال اجرا نیست."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 بار پردازنده {{ .Percent }}% بیشتر از آستانه است {{ .Threshold }}%"
|
||||
@@ -640,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }} : با موفقیت غیرفعال شد."
|
||||
"askToAddUserId" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nشناسه کاربری شما: <code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "یک مشتری برای ورودی {{ .Inbound }} انتخاب کنید"
|
||||
"chooseInbound" = "یک ورودی انتخاب کنید"
|
||||
"chooseInbound" = "یک ورودی انتخاب کنید"
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Port Tujuan"
|
||||
"targetAddress" = "Alamat Target"
|
||||
"monitorDesc" = "Biarkan kosong untuk mendengarkan semua IP"
|
||||
"meansNoLimit" = " = Unlimited. (unit: GB)"
|
||||
"meansNoLimit" = "= Unlimited. (unit: GB)"
|
||||
"totalFlow" = "Total Aliran"
|
||||
"leaveBlankToNeverExpire" = "Biarkan kosong untuk tidak pernah kedaluwarsa"
|
||||
"noRecommendKeepDefault" = "Disarankan untuk tetap menggunakan pengaturan default"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "Log histori IP. (untuk mengaktifkan masuk setelah menonaktifkan, hapus log)"
|
||||
"IPLimitlogclear" = "Hapus Log"
|
||||
"setDefaultCert" = "Atur Sertifikat dari Panel"
|
||||
"xtlsDesc" = "Xray harus versi 1.7.5"
|
||||
"realityDesc" = "Xray harus versi 1.8.0+"
|
||||
"telegramDesc" = "Harap berikan ID Obrolan Telegram. (gunakan perintah '/id' di bot) atau (@userinfobot)"
|
||||
"subscriptionDesc" = "Untuk menemukan URL langganan Anda, buka 'Rincian'. Selain itu, Anda dapat menggunakan nama yang sama untuk beberapa klien."
|
||||
"info" = "Info"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "Token bot Telegram yang diperoleh dari '@BotFather'."
|
||||
"telegramProxy" = "Proxy SOCKS"
|
||||
"telegramProxyDesc" = "Mengaktifkan proxy SOCKS5 untuk terhubung ke Telegram. (sesuaikan pengaturan sesuai panduan)"
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
"telegramAPIServerDesc" = "Server API Telegram yang akan digunakan. Biarkan kosong untuk menggunakan server default."
|
||||
"telegramChatId" = "ID Obrolan Admin"
|
||||
"telegramChatIdDesc" = "ID Obrolan Admin Telegram. (dipisahkan koma)(dapatkan di sini @userinfobot) atau (gunakan perintah '/id' di bot)"
|
||||
"telegramNotifyTime" = "Waktu Notifikasi"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Fragmentasi"
|
||||
"fragmentDesc" = "Aktifkan fragmentasi untuk paket hello TLS"
|
||||
"fragmentSett" = "Pengaturan Fragmentasi"
|
||||
"noiseDesc" = "Aktifkan Noise."
|
||||
"noiseSett" = "Pengaturan Noise"
|
||||
"noisesDesc" = "Aktifkan Noises."
|
||||
"noisesSett" = "Pengaturan Noises"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Mengirimkan beberapa aliran data independen dalam aliran data yang sudah ada."
|
||||
"muxSett" = "Pengaturan Mux"
|
||||
"direct" = "Koneksi langsung"
|
||||
"directDesc" = "Secara langsung membuat koneksi dengan domain atau rentang IP negara tertentu."
|
||||
"directSett" = "Opsi Koneksi Langsung"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Konfigurasi Xray"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Log dapat mempengaruhi efisiensi server Anda. Disarankan untuk mengaktifkannya dengan bijak hanya jika diperlukan"
|
||||
"blockConfigs" = "Pelindung"
|
||||
"blockConfigsDesc" = "Opsi ini akan memblokir lalu lintas berdasarkan protokol dan situs web yang diminta."
|
||||
"blockCountryConfigs" = "Blokir Negara"
|
||||
"blockCountryConfigsDesc" = "Opsi ini akan memblokir lalu lintas berdasarkan negara yang diminta."
|
||||
"directCountryConfigs" = "Langsung ke Negara"
|
||||
"directCountryConfigsDesc" = "Koneksi langsung memastikan bahwa lalu lintas tertentu tidak diarahkan melalui server lain."
|
||||
"ipv4Configs" = "Pengalihan IPv4"
|
||||
"ipv4ConfigsDesc" = "Opsi ini akan mengalihkan lalu lintas berdasarkan tujuan tertentu melalui IPv4."
|
||||
"warpConfigs" = "Pengalihan WARP"
|
||||
"warpConfigsDesc" = "Opsi ini akan mengalihkan lalu lintas berdasarkan tujuan tertentu melalui WARP."
|
||||
"basicRouting" = "Perutean Dasar"
|
||||
"blockConnectionsConfigsDesc" = "Opsi ini akan memblokir lalu lintas berdasarkan negara yang diminta."
|
||||
"directConnectionsConfigsDesc" = "Koneksi langsung memastikan bahwa lalu lintas tertentu tidak dialihkan melalui server lain."
|
||||
"blockips" = "Blokir IP"
|
||||
"blockdomains" = "Blokir Domain"
|
||||
"directips" = "IP Langsung"
|
||||
"directdomains" = "Domain Langsung"
|
||||
"ipv4Routing" = "Perutean IPv4"
|
||||
"ipv4RoutingDesc" = "Opsi ini akan mengalihkan lalu lintas berdasarkan tujuan tertentu melalui IPv4."
|
||||
"warpRouting" = "Perutean WARP"
|
||||
"warpRoutingDesc" = "Opsi ini akan mengalihkan lalu lintas berdasarkan tujuan tertentu melalui WARP."
|
||||
"Template" = "Template Konfigurasi Xray Lanjutan"
|
||||
"TemplateDesc" = "File konfigurasi Xray akhir akan dibuat berdasarkan template ini."
|
||||
"FreedomStrategy" = "Strategi Protokol Freedom"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "Atur strategi pengalihan lalu lintas keseluruhan untuk menyelesaikan semua permintaan."
|
||||
"Torrent" = "Blokir Protokol BitTorrent"
|
||||
"TorrentDesc" = "Memblokir protokol BitTorrent."
|
||||
"PrivateIp" = "Blokir Koneksi ke IP Pribadi"
|
||||
"PrivateIpDesc" = "Memblokir pembentukan koneksi ke rentang IP pribadi."
|
||||
"Ads" = "Blokir Iklan"
|
||||
"AdsDesc" = "Memblokir situs web periklanan."
|
||||
"Family" = "Proteksi Keluarga"
|
||||
"FamilyDesc" = "Memblokir konten dewasa dan situs web berbahaya."
|
||||
"Security" = "Pelindung Keamanan"
|
||||
"SecurityDesc" = "Memblokir situs web malware, phishing, dan penambang kripto."
|
||||
"Speedtest" = "Blokir Speedtest"
|
||||
"SpeedtestDesc" = "Memblokir pembentukan koneksi ke situs web speedtest."
|
||||
"IRIp" = "Blokir Koneksi ke IP Iran"
|
||||
"IRIpDesc" = "Memblokir pembentukan koneksi ke rentang IP Iran."
|
||||
"IRDomain" = "Blokir Koneksi ke Domain Iran"
|
||||
"IRDomainDesc" = "Memblokir pembentukan koneksi ke domain Iran."
|
||||
"ChinaIp" = "Blokir Koneksi ke IP China"
|
||||
"ChinaIpDesc" = "Memblokir pembentukan koneksi ke rentang IP China."
|
||||
"ChinaDomain" = "Blokir Koneksi ke Domain China"
|
||||
"ChinaDomainDesc" = "Memblokir pembentukan koneksi ke domain China."
|
||||
"RussiaIp" = "Blokir Koneksi ke IP Rusia"
|
||||
"RussiaIpDesc" = "Memblokir pembentukan koneksi ke rentang IP Rusia."
|
||||
"RussiaDomain" = "Blokir Koneksi ke Domain Rusia"
|
||||
"RussiaDomainDesc" = "Memblokir pembentukan koneksi ke domain Rusia."
|
||||
"VNIp" = "Blokir Koneksi ke IP Vietnam"
|
||||
"VNIpDesc" = "Memblokir pembentukan koneksi ke rentang IP Vietnam."
|
||||
"VNDomain" = "Blokir Koneksi ke Domain Vietnam"
|
||||
"VNDomainDesc" = "Memblokir pembentukan koneksi ke domain Vietnam."
|
||||
"DirectIRIp" = "Koneksi Langsung ke IP Iran"
|
||||
"DirectIRIpDesc" = "Membentuk koneksi langsung ke rentang IP Iran."
|
||||
"DirectIRDomain" = "Koneksi Langsung ke Domain Iran"
|
||||
"DirectIRDomainDesc" = "Membentuk koneksi langsung ke domain Iran."
|
||||
"DirectChinaIp" = "Koneksi Langsung ke IP China"
|
||||
"DirectChinaIpDesc" = "Membentuk koneksi langsung ke rentang IP China."
|
||||
"DirectChinaDomain" = "Koneksi Langsung ke Domain China"
|
||||
"DirectChinaDomainDesc" = "Membentuk koneksi langsung ke domain China."
|
||||
"DirectRussiaIp" = "Koneksi Langsung ke IP Rusia"
|
||||
"DirectRussiaIpDesc" = "Membentuk koneksi langsung ke rentang IP Rusia."
|
||||
"DirectRussiaDomain" = "Koneksi Langsung ke Domain Rusia"
|
||||
"DirectRussiaDomainDesc" = "Membentuk koneksi langsung ke domain Rusia."
|
||||
"DirectVNIp" = "Koneksi Langsung ke IP Vietnam"
|
||||
"DirectVNIpDesc" = "Membentuk koneksi langsung ke rentang IP Vietnam."
|
||||
"DirectVNDomain" = "Koneksi Langsung ke Domain Vietnam"
|
||||
"DirectVNDomainDesc" = "Membentuk koneksi langsung ke domain Vietnam."
|
||||
"GoogleIPv4" = "Google"
|
||||
"GoogleIPv4Desc" = "Rute lalu lintas ke Google melalui IPv4."
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "Rute lalu lintas ke Netflix melalui IPv4."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Tambahkan pengalihan untuk Google melalui WARP."
|
||||
"OpenAIWARP" = "ChatGPT"
|
||||
"OpenAIWARPDesc" = "Rute lalu lintas ke ChatGPT melalui WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Rute lalu lintas ke Netflix melalui WARP."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Merutekan lalu lintas ke Meta (Instagram, Facebook, WhatsApp, Threads,...) melalui WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Merutekan lalu lintas ke Apple melalui WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Merutekan lalu lintas ke Reddit melalui WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Rute lalu lintas ke Spotify melalui WARP."
|
||||
"IRWARP" = "Domain Iran"
|
||||
"IRWARPDesc" = "Rute lalu lintas ke domain Iran melalui WARP."
|
||||
"Inbounds" = "Masuk"
|
||||
"InboundsDesc" = "Menerima klien tertentu."
|
||||
"Outbounds" = "Keluar"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "Jalur file untuk log akses. Nilai khusus 'tidak ada' menonaktifkan log akses"
|
||||
"errorLog" = "Catatan eror"
|
||||
"errorLogDesc" = "Jalur file untuk log kesalahan. Nilai khusus 'tidak ada' menonaktifkan log kesalahan"
|
||||
"dnsLog" = "Log DNS"
|
||||
"dnsLogDesc" = "Apakah akan mengaktifkan log kueri DNS"
|
||||
"maskAddress" = "Alamat Masker"
|
||||
"maskAddressDesc" = "Masker alamat IP, ketika diaktifkan, akan secara otomatis mengganti alamat IP yang muncul di log."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "Pertama"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Tambahkan Server"
|
||||
"edit" = "Sunting Server"
|
||||
"domains" = "Domains"
|
||||
"expectIPs" = "IP yang Diharapkan"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Tambahkan DNS Palsu"
|
||||
@@ -534,9 +482,13 @@
|
||||
"welcome" = "🤖 Selamat datang di <b>{{.Hostname }}</b> bot managemen.\r\n"
|
||||
"status" = "✅ Bot dalam keadaan baik!"
|
||||
"usage" = "❗ Harap berikan teks untuk mencari!"
|
||||
"getID" = "🆔 ID Anda:<code>{{.ID }}</code>"
|
||||
"helpAdminCommands" = "Untuk mencari email klien:\r\n<code>/usage [Email]</code>\r\n\r\nUntuk mencari inbound (dengan statistik klien):\r\n<code>/inbound [Catatan]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>"
|
||||
"getID" = "🆔 ID Anda: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Untuk memulai ulang Xray Core:\r\n<code>/restart force</code>\r\n\r\nUntuk mencari email klien:\r\n<code>/usage [Email]</code>\r\n\r\nUntuk mencari inbound (dengan statistik klien):\r\n<code>/inbound [Catatan]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "Untuk mencari statistik, gunakan perintah berikut:\r\n<code>/usage [Email]</code>\r\n\r\nID Obrolan Telegram:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ Operasi berhasil!"
|
||||
"restartFailed" = "❗ Kesalahan dalam operasi.\r\n\r\n<code>Error: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core tidak berjalan."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 Beban CPU {{ .Percent }}% melebihi batas {{ .Threshold }}%"
|
||||
@@ -640,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }}: Dinonaktifkan dengan berhasil."
|
||||
"askToAddUserId" = "Konfigurasi Anda tidak ditemukan!\r\nSilakan minta admin Anda untuk menggunakan ChatID Telegram Anda dalam konfigurasi Anda.\r\n\r\nChatID Pengguna Anda: <code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "Pilih Klien untuk Inbound {{ .Inbound }}"
|
||||
"chooseInbound" = "Pilih Inbound"
|
||||
"chooseInbound" = "Pilih Inbound"
|
||||
|
||||
595
web/translation/translate.ja_JP.toml
Normal file
595
web/translation/translate.ja_JP.toml
Normal file
@@ -0,0 +1,595 @@
|
||||
"username" = "ユーザー名"
|
||||
"password" = "パスワード"
|
||||
"login" = "ログイン"
|
||||
"confirm" = "確認"
|
||||
"cancel" = "キャンセル"
|
||||
"close" = "閉じる"
|
||||
"copy" = "コピー"
|
||||
"copied" = "コピー済み"
|
||||
"download" = "ダウンロード"
|
||||
"remark" = "備考"
|
||||
"enable" = "有効化"
|
||||
"protocol" = "プロトコル"
|
||||
"search" = "検索"
|
||||
"filter" = "フィルター"
|
||||
"loading" = "読み込み中..."
|
||||
"second" = "秒"
|
||||
"minute" = "分"
|
||||
"hour" = "時間"
|
||||
"day" = "日"
|
||||
"check" = "確認"
|
||||
"indefinite" = "無期限"
|
||||
"unlimited" = "無制限"
|
||||
"none" = "なし"
|
||||
"qrCode" = "QRコード"
|
||||
"info" = "詳細情報"
|
||||
"edit" = "編集"
|
||||
"delete" = "削除"
|
||||
"reset" = "リセット"
|
||||
"copySuccess" = "コピー成功"
|
||||
"sure" = "確定"
|
||||
"encryption" = "暗号化"
|
||||
"transmission" = "伝送"
|
||||
"host" = "ホスト"
|
||||
"path" = "パス"
|
||||
"camouflage" = "偽装"
|
||||
"status" = "ステータス"
|
||||
"enabled" = "有効"
|
||||
"disabled" = "無効"
|
||||
"depleted" = "消耗済み"
|
||||
"depletingSoon" = "間もなく消耗"
|
||||
"offline" = "オフライン"
|
||||
"online" = "オンライン"
|
||||
"domainName" = "ドメイン名"
|
||||
"monitor" = "監視"
|
||||
"certificate" = "証明書"
|
||||
"fail" = "失敗"
|
||||
"success" = "成功"
|
||||
"getVersion" = "バージョン取得"
|
||||
"install" = "インストール"
|
||||
"clients" = "クライアント"
|
||||
"usage" = "利用状況"
|
||||
"secretToken" = "シークレットトークン"
|
||||
"remained" = "残り"
|
||||
"security" = "セキュリティ"
|
||||
"secAlertTitle" = "セキュリティアラート"
|
||||
"secAlertSsl" = "この接続は安全ではありません。TLSを有効にしてデータ保護を行うまで、機密情報を入力しないでください。"
|
||||
"secAlertConf" = "一部の設定は脆弱です。潜在的な脆弱性を防ぐために、セキュリティプロトコルを強化することをお勧めします。"
|
||||
"secAlertSSL" = "セキュアな接続がありません。データ保護のためにTLS証明書をインストールしてください。"
|
||||
"secAlertPanelPort" = "デフォルトのポートにはセキュリティリスクがあります。ランダムなポートまたは特定のポートを設定してください。"
|
||||
"secAlertPanelURI" = "デフォルトのURIパスは安全ではありません。複雑なURIパスを設定してください。"
|
||||
"secAlertSubURI" = "サブスクリプションのデフォルトURIパスは安全ではありません。複雑なURIパスを設定してください。"
|
||||
"secAlertSubJsonURI" = "JSONサブスクリプションのデフォルトURIパスは安全ではありません。複雑なURIパスを設定してください。"
|
||||
|
||||
[menu]
|
||||
"dashboard" = "ダッシュボード"
|
||||
"inbounds" = "インバウンド一覧"
|
||||
"settings" = "パネル設定"
|
||||
"xray" = "Xray設定"
|
||||
"logout" = "ログアウト"
|
||||
"link" = "リンク管理"
|
||||
|
||||
[pages.login]
|
||||
"hello" = "こんにちは"
|
||||
"title" = "ようこそ"
|
||||
"loginAgain" = "ログインセッションが切れました。再度ログインしてください。"
|
||||
|
||||
[pages.login.toasts]
|
||||
"invalidFormData" = "データ形式エラー"
|
||||
"emptyUsername" = "ユーザー名を入力してください"
|
||||
"emptyPassword" = "パスワードを入力してください"
|
||||
"wrongUsernameOrPassword" = "ユーザー名またはパスワードが間違っています"
|
||||
"successLogin" = "ログイン成功"
|
||||
|
||||
[pages.index]
|
||||
"title" = "システムステータス"
|
||||
"memory" = "メモリ"
|
||||
"hard" = "ハードディスク"
|
||||
"xrayStatus" = "Xray"
|
||||
"stopXray" = "停止"
|
||||
"restartXray" = "再起動"
|
||||
"xraySwitch" = "バージョン"
|
||||
"xraySwitchClick" = "切り替えるバージョンを選択してください"
|
||||
"xraySwitchClickDesk" = "慎重に選択してください。古いバージョンは現在の設定と互換性がない可能性があります。"
|
||||
"operationHours" = "システム稼働時間"
|
||||
"systemLoad" = "システム負荷"
|
||||
"systemLoadDesc" = "過去1、5、15分間のシステム平均負荷"
|
||||
"connectionTcpCountDesc" = "システム内のすべてのTCP接続数"
|
||||
"connectionUdpCountDesc" = "システム内のすべてのUDP接続数"
|
||||
"connectionCount" = "接続数"
|
||||
"upSpeed" = "総アップロード速度"
|
||||
"downSpeed" = "総ダウンロード速度"
|
||||
"totalSent" = "システム起動以降の送信データ量"
|
||||
"totalReceive" = "システム起動以降の受信データ量"
|
||||
"xraySwitchVersionDialog" = "Xrayバージョン切り替え"
|
||||
"xraySwitchVersionDialogDesc" = "Xrayのバージョンを切り替えますか?"
|
||||
"dontRefresh" = "インストール中、このページをリロードしないでください"
|
||||
"logs" = "ログ"
|
||||
"config" = "設定"
|
||||
"backup" = "バックアップと復元"
|
||||
"backupTitle" = "データベースのバックアップと復元"
|
||||
"backupDescription" = "データベースを復元する前にバックアップすることをお勧めします"
|
||||
"exportDatabase" = "バックアップ"
|
||||
"importDatabase" = "復元"
|
||||
|
||||
[pages.inbounds]
|
||||
"title" = "インバウンド一覧"
|
||||
"totalDownUp" = "総アップロード / ダウンロード"
|
||||
"totalUsage" = "総使用量"
|
||||
"inboundCount" = "インバウンド数"
|
||||
"operate" = "メニュー"
|
||||
"enable" = "有効化"
|
||||
"remark" = "備考"
|
||||
"protocol" = "プロトコル"
|
||||
"port" = "ポート"
|
||||
"traffic" = "トラフィック"
|
||||
"details" = "詳細情報"
|
||||
"transportConfig" = "トランスポート設定"
|
||||
"expireDate" = "有効期限"
|
||||
"resetTraffic" = "トラフィックリセット"
|
||||
"addInbound" = "インバウンド追加"
|
||||
"generalActions" = "一般操作"
|
||||
"create" = "追加"
|
||||
"update" = "更新"
|
||||
"modifyInbound" = "インバウンド修正"
|
||||
"deleteInbound" = "インバウンド削除"
|
||||
"deleteInboundContent" = "インバウンドを削除してもよろしいですか?"
|
||||
"deleteClient" = "クライアント削除"
|
||||
"deleteClientContent" = "クライアントを削除してもよろしいですか?"
|
||||
"resetTrafficContent" = "トラフィックをリセットしてもよろしいですか?"
|
||||
"copyLink" = "リンクをコピー"
|
||||
"address" = "アドレス"
|
||||
"network" = "ネットワーク"
|
||||
"destinationPort" = "宛先ポート"
|
||||
"targetAddress" = "宛先アドレス"
|
||||
"monitorDesc" = "空白にするとすべてのIPを監視"
|
||||
"meansNoLimit" = "= 無制限(単位:GB)"
|
||||
"totalFlow" = "総トラフィック"
|
||||
"leaveBlankToNeverExpire" = "空白にすると期限なし"
|
||||
"noRecommendKeepDefault" = "デフォルト値を保持することをお勧めします"
|
||||
"certificatePath" = "ファイルパス"
|
||||
"certificateContent" = "ファイル内容"
|
||||
"publicKey" = "公開鍵"
|
||||
"privatekey" = "秘密鍵"
|
||||
"clickOnQRcode" = "QRコードをクリックしてコピー"
|
||||
"client" = "クライアント"
|
||||
"export" = "リンクエクスポート"
|
||||
"clone" = "複製"
|
||||
"cloneInbound" = "複製"
|
||||
"cloneInboundContent" = "このインバウンドルールは、ポート(Port)、リスニングIP(Listening IP)、クライアント(Clients)を除くすべての設定がクローンされます"
|
||||
"cloneInboundOk" = "クローン作成"
|
||||
"resetAllTraffic" = "すべてのインバウンドトラフィックをリセット"
|
||||
"resetAllTrafficTitle" = "すべてのインバウンドトラフィックをリセット"
|
||||
"resetAllTrafficContent" = "すべてのインバウンドトラフィックをリセットしてもよろしいですか?"
|
||||
"resetInboundClientTraffics" = "クライアントトラフィックをリセット"
|
||||
"resetInboundClientTrafficTitle" = "すべてのクライアントトラフィックをリセット"
|
||||
"resetInboundClientTrafficContent" = "このインバウンドクライアントのすべてのトラフィックをリセットしてもよろしいですか?"
|
||||
"resetAllClientTraffics" = "すべてのクライアントトラフィックをリセット"
|
||||
"resetAllClientTrafficTitle" = "すべてのクライアントトラフィックをリセット"
|
||||
"resetAllClientTrafficContent" = "すべてのクライアントのトラフィックをリセットしてもよろしいですか?"
|
||||
"delDepletedClients" = "トラフィックが尽きたクライアントを削除"
|
||||
"delDepletedClientsTitle" = "トラフィックが尽きたクライアントを削除"
|
||||
"delDepletedClientsContent" = "トラフィックが尽きたすべてのクライアントを削除してもよろしいですか?"
|
||||
"email" = "メールアドレス"
|
||||
"emailDesc" = "メールアドレスは一意でなければなりません"
|
||||
"IPLimit" = "IP制限"
|
||||
"IPLimitDesc" = "設定値を超えるとインバウンドトラフィックが無効になります。(0 = 無効)"
|
||||
"IPLimitlog" = "IPログ"
|
||||
"IPLimitlogDesc" = "IP履歴ログ(無効なインバウンドトラフィックを有効にするには、ログをクリアしてください)"
|
||||
"IPLimitlogclear" = "ログをクリア"
|
||||
"setDefaultCert" = "パネル設定から証明書を設定"
|
||||
"telegramDesc" = "TelegramチャットIDを提供してください。(ボットで'/id'コマンドを使用)または(@userinfobot)"
|
||||
"subscriptionDesc" = "サブスクリプションURLを見つけるには、“詳細情報”に移動してください。また、複数のクライアントに同じ名前を使用することができます。"
|
||||
"info" = "情報"
|
||||
"same" = "同じ"
|
||||
"inboundData" = "インバウンドデータ"
|
||||
"exportInbound" = "インバウンドルールをエクスポート"
|
||||
"import" = "インポート"
|
||||
"importInbound" = "インバウンドルールをインポート"
|
||||
|
||||
[pages.client]
|
||||
"add" = "クライアント追加"
|
||||
"edit" = "クライアント編集"
|
||||
"submitAdd" = "クライアント追加"
|
||||
"submitEdit" = "変更を保存"
|
||||
"clientCount" = "クライアント数"
|
||||
"bulk" = "一括作成"
|
||||
"method" = "方法"
|
||||
"first" = "最初"
|
||||
"last" = "最後"
|
||||
"prefix" = "プレフィックス"
|
||||
"postfix" = "サフィックス"
|
||||
"delayedStart" = "初回使用後に開始"
|
||||
"expireDays" = "期間"
|
||||
"days" = "日"
|
||||
"renew" = "自動更新"
|
||||
"renewDesc" = "期限が切れた後に自動更新。(0 = 無効)(単位:日)"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "取得"
|
||||
|
||||
[pages.inbounds.stream.general]
|
||||
"request" = "リクエスト"
|
||||
"response" = "レスポンス"
|
||||
"name" = "名前"
|
||||
"value" = "値"
|
||||
|
||||
[pages.inbounds.stream.tcp]
|
||||
"version" = "バージョン"
|
||||
"method" = "方法"
|
||||
"path" = "パス"
|
||||
"status" = "ステータス"
|
||||
"statusDescription" = "ステータス説明"
|
||||
"requestHeader" = "リクエストヘッダー"
|
||||
"responseHeader" = "レスポンスヘッダー"
|
||||
|
||||
[pages.settings]
|
||||
"title" = "パネル設定"
|
||||
"save" = "保存"
|
||||
"infoDesc" = "ここでのすべての変更は、保存してパネルを再起動する必要があります"
|
||||
"restartPanel" = "パネル再起動"
|
||||
"restartPanelDesc" = "パネルを再起動してもよろしいですか?再起動後にパネルにアクセスできない場合は、サーバーでパネルログを確認してください"
|
||||
"actions" = "操作"
|
||||
"resetDefaultConfig" = "デフォルト設定にリセット"
|
||||
"panelSettings" = "一般"
|
||||
"securitySettings" = "セキュリティ設定"
|
||||
"TGBotSettings" = "Telegramボット設定"
|
||||
"panelListeningIP" = "パネル監視IP"
|
||||
"panelListeningIPDesc" = "デフォルトではすべてのIPを監視する"
|
||||
"panelListeningDomain" = "パネル監視ドメイン"
|
||||
"panelListeningDomainDesc" = "デフォルトで空白の場合、すべてのドメインとIPアドレスを監視する"
|
||||
"panelPort" = "パネル監視ポート"
|
||||
"panelPortDesc" = "再起動で有効"
|
||||
"publicKeyPath" = "パネル証明書公開鍵ファイルパス"
|
||||
"publicKeyPathDesc" = "'/'で始まる絶対パスを入力"
|
||||
"privateKeyPath" = "パネル証明書秘密鍵ファイルパス"
|
||||
"privateKeyPathDesc" = "'/'で始まる絶対パスを入力"
|
||||
"panelUrlPath" = "パネルURLルートパス"
|
||||
"panelUrlPathDesc" = "'/'で始まり、'/'で終わる必要があります"
|
||||
"pageSize" = "ページサイズ"
|
||||
"pageSizeDesc" = "インバウンドテーブルのページサイズを定義します。0を設定すると無効化されます"
|
||||
"remarkModel" = "備考モデルと区切り記号"
|
||||
"datepicker" = "日付ピッカー"
|
||||
"datepickerPlaceholder" = "日付を選択"
|
||||
"datepickerDescription" = "日付選択カレンダーで有効期限を指定する"
|
||||
"sampleRemark" = "備考の例"
|
||||
"oldUsername" = "旧ユーザー名"
|
||||
"currentPassword" = "旧パスワード"
|
||||
"newUsername" = "新しいユーザー名"
|
||||
"newPassword" = "新しいパスワード"
|
||||
"telegramBotEnable" = "Telegramボットを有効にする"
|
||||
"telegramBotEnableDesc" = "Telegramボット機能を有効にする"
|
||||
"telegramToken" = "Telegramボットトークン"
|
||||
"telegramTokenDesc" = "'@BotFather'から取得したTelegramボットトークン"
|
||||
"telegramProxy" = "SOCKS5プロキシ"
|
||||
"telegramProxyDesc" = "SOCKS5プロキシを有効にしてTelegramに接続する(ガイドに従って設定を調整)"
|
||||
"telegramAPIServer" = "Telegram APIサーバー"
|
||||
"telegramAPIServerDesc" = "使用するTelegram APIサーバー。空白の場合はデフォルトサーバーを使用する"
|
||||
"telegramChatId" = "管理者チャットID"
|
||||
"telegramChatIdDesc" = "Telegram管理者チャットID(複数の場合はカンマで区切る)@userinfobotで取得するか、ボットで'/id'コマンドを使用して取得する"
|
||||
"telegramNotifyTime" = "通知時間"
|
||||
"telegramNotifyTimeDesc" = "定期的なTelegramボット通知時間を設定する(crontab時間形式を使用)"
|
||||
"tgNotifyBackup" = "データベースバックアップ"
|
||||
"tgNotifyBackupDesc" = "レポート付きのデータベースバックアップファイルを送信"
|
||||
"tgNotifyLogin" = "ログイン通知"
|
||||
"tgNotifyLoginDesc" = "誰かがパネルにログインしようとしたときに、ユーザー名、IPアドレス、時間を表示する"
|
||||
"sessionMaxAge" = "セッション期間"
|
||||
"sessionMaxAgeDesc" = "ログイン状態を保持する期間(単位:分)"
|
||||
"expireTimeDiff" = "有効期限通知のしきい値"
|
||||
"expireTimeDiffDesc" = "このしきい値に達した場合、有効期限に関する通知を受け取る(単位:日)"
|
||||
"trafficDiff" = "トラフィック消耗しきい値"
|
||||
"trafficDiffDesc" = "このしきい値に達した場合、トラフィック消耗に関する通知を受け取る(単位:GB)"
|
||||
"tgNotifyCpu" = "CPU負荷通知しきい値"
|
||||
"tgNotifyCpuDesc" = "CPU負荷がこのしきい値を超えた場合、通知を受け取る(単位:%)"
|
||||
"timeZone" = "タイムゾーン"
|
||||
"timeZoneDesc" = "定時タスクはこのタイムゾーンの時間に従って実行される"
|
||||
"subSettings" = "サブスクリプション設定"
|
||||
"subEnable" = "サブスクリプションサービスを有効にする"
|
||||
"subEnableDesc" = "サブスクリプションサービス機能を有効にする"
|
||||
"subListen" = "監視IP"
|
||||
"subListenDesc" = "サブスクリプションサービスが監視するIPアドレス(空白にするとすべてのIPを監視)"
|
||||
"subPort" = "監視ポート"
|
||||
"subPortDesc" = "サブスクリプションサービスが監視するポート番号(使用されていないポートである必要があります)"
|
||||
"subCertPath" = "公開鍵パス"
|
||||
"subCertPathDesc" = "サブスクリプションサービスで使用する公開鍵ファイルのパス('/'で始まる)"
|
||||
"subKeyPath" = "秘密鍵パス"
|
||||
"subKeyPathDesc" = "サブスクリプションサービスで使用する秘密鍵ファイルのパス('/'で始まる)"
|
||||
"subPath" = "URIパス"
|
||||
"subPathDesc" = "サブスクリプションサービスで使用するURIパス('/'で始まり、'/'で終わる)"
|
||||
"subDomain" = "監視ドメイン"
|
||||
"subDomainDesc" = "サブスクリプションサービスが監視するドメイン(空白にするとすべてのドメインとIPを監視)"
|
||||
"subUpdates" = "更新間隔"
|
||||
"subUpdatesDesc" = "クライアントアプリケーションでサブスクリプションURLの更新間隔(単位:時間)"
|
||||
"subEncrypt" = "エンコード"
|
||||
"subEncryptDesc" = "サブスクリプションサービスが返す内容をBase64エンコードする"
|
||||
"subShowInfo" = "利用情報を表示"
|
||||
"subShowInfoDesc" = "クライアントアプリで残りのトラフィックと日付情報を表示する"
|
||||
"subURI" = "リバースプロキシURI"
|
||||
"subURIDesc" = "プロキシ後ろのサブスクリプションURLのURIパスに使用する"
|
||||
"fragment" = "フラグメント"
|
||||
"fragmentDesc" = "TLS helloパケットのフラグメントを有効にする"
|
||||
"fragmentSett" = "設定"
|
||||
"noisesDesc" = "Noisesを有効にする"
|
||||
"noisesSett" = "Noises設定"
|
||||
"mux" = "マルチプレクサ"
|
||||
"muxDesc" = "確立されたストリーム内で複数の独立したストリームを伝送する"
|
||||
"muxSett" = "マルチプレクサ設定"
|
||||
"direct" = "直接接続"
|
||||
"directDesc" = "特定の国のドメインまたはIP範囲に直接接続する"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray 設定"
|
||||
"save" = "保存"
|
||||
"restart" = "Xray 再起動"
|
||||
"basicTemplate" = "基本設定"
|
||||
"advancedTemplate" = "高度な設定"
|
||||
"generalConfigs" = "一般設定"
|
||||
"generalConfigsDesc" = "これらのオプションは一般設定を決定します"
|
||||
"logConfigs" = "ログ"
|
||||
"logConfigsDesc" = "ログはサーバーのパフォーマンスに影響を与える可能性があるため、必要な場合にのみ有効にすることをお勧めします"
|
||||
"blockConfigs" = "防御フィルター"
|
||||
"blockConfigsDesc" = "これらのオプションは、特定のプロトコルやウェブサイトへのユーザー接続をブロックします"
|
||||
"basicRouting" = "基本ルーティング"
|
||||
"blockConnectionsConfigsDesc" = "これらのオプションにより、特定のリクエスト元の国に基づいてトラフィックをブロックします。"
|
||||
"directConnectionsConfigsDesc" = "直接接続により、特定のトラフィックが他のサーバーを経由しないようにします。"
|
||||
"blockips" = "IPをブロック"
|
||||
"blockdomains" = "ドメインをブロック"
|
||||
"directips" = "直接IP"
|
||||
"directdomains" = "直接ドメイン"
|
||||
"ipv4Routing" = "IPv4 ルーティング"
|
||||
"ipv4RoutingDesc" = "このオプションはIPv4のみを介してターゲットドメインへルーティングします"
|
||||
"warpRouting" = "WARP ルーティング"
|
||||
"warpRoutingDesc" = "注意:これらのオプションを使用する前に、パネルのGitHubの手順に従って、サーバーにsocks5プロキシモードでWARPをインストールしてください。WARPはCloudflareサーバー経由でトラフィックをウェブサイトにルーティングします。"
|
||||
"Template" = "高度なXray設定テンプレート"
|
||||
"TemplateDesc" = "最終的なXray設定ファイルはこのテンプレートに基づいて生成されます"
|
||||
"FreedomStrategy" = "Freedom プロトコル戦略"
|
||||
"FreedomStrategyDesc" = "Freedomプロトコル内のネットワークの出力戦略を設定する"
|
||||
"RoutingStrategy" = "ルーティングドメイン戦略設定"
|
||||
"RoutingStrategyDesc" = "DNS解決の全体的なルーティング戦略を設定する"
|
||||
"Torrent" = "BitTorrent プロトコルをブロック"
|
||||
"TorrentDesc" = "BitTorrentの使用を禁止する"
|
||||
"Family" = "ファミリー保護"
|
||||
"FamilyDesc" = "アダルトコンテンツや悪意のあるサイトをブロックする"
|
||||
"Inbounds" = "インバウンドルール"
|
||||
"InboundsDesc" = "特定のクライアントからのトラフィックを受け入れる"
|
||||
"Outbounds" = "アウトバウンドルール"
|
||||
"Balancers" = "負荷分散"
|
||||
"OutboundsDesc" = "アウトバウンドトラフィックの送信方法を設定する"
|
||||
"Routings" = "ルーティングルール"
|
||||
"RoutingsDesc" = "各ルールの優先順位が重要です"
|
||||
"completeTemplate" = "すべて"
|
||||
"logLevel" = "ログレベル"
|
||||
"logLevelDesc" = "エラーログのレベルを指定し、記録する情報を示します"
|
||||
"accessLog" = "アクセスログ"
|
||||
"accessLogDesc" = "アクセスログのファイルパス。特殊値 'none' はアクセスログを無効にします"
|
||||
"errorLog" = "エラーログ"
|
||||
"errorLogDesc" = "エラーログのファイルパス。特殊値 'none' はエラーログを無効にします"
|
||||
"dnsLog" = "DNS ログ"
|
||||
"dnsLogDesc" = "DNSクエリのログを有効にするかどうか"
|
||||
"maskAddress" = "アドレスをマスク"
|
||||
"maskAddressDesc" = "IPアドレスをマスクし、有効にするとログに表示されるIPアドレスを自動的に置き換えます"
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "最初"
|
||||
"last" = "最後"
|
||||
"up" = "上へ"
|
||||
"down" = "下へ"
|
||||
"source" = "ソース"
|
||||
"dest" = "宛先アドレス"
|
||||
"inbound" = "インバウンド"
|
||||
"outbound" = "アウトバウンド"
|
||||
"balancer" = "負荷分散"
|
||||
"info" = "情報"
|
||||
"add" = "ルール追加"
|
||||
"edit" = "ルール編集"
|
||||
"useComma" = "カンマ区切りの項目"
|
||||
|
||||
[pages.xray.outbound]
|
||||
"addOutbound" = "アウトバウンド追加"
|
||||
"addReverse" = "リバース追加"
|
||||
"editOutbound" = "アウトバウンド編集"
|
||||
"editReverse" = "リバース編集"
|
||||
"tag" = "タグ"
|
||||
"tagDesc" = "一意のタグ"
|
||||
"address" = "アドレス"
|
||||
"reverse" = "リバース"
|
||||
"domain" = "ドメイン"
|
||||
"type" = "タイプ"
|
||||
"bridge" = "ブリッジ"
|
||||
"portal" = "ポータル"
|
||||
"intercon" = "インターコネクション"
|
||||
"settings" = "設定"
|
||||
"accountInfo" = "アカウント情報"
|
||||
"outboundStatus" = "アウトバウンドステータス"
|
||||
"sendThrough" = "送信経路"
|
||||
|
||||
[pages.xray.balancer]
|
||||
"addBalancer" = "負荷分散追加"
|
||||
"editBalancer" = "負荷分散編集"
|
||||
"balancerStrategy" = "戦略"
|
||||
"balancerSelectors" = "セレクター"
|
||||
"tag" = "タグ"
|
||||
"tagDesc" = "一意のタグ"
|
||||
"balancerDesc" = "balancerTagとoutboundTagは同時に使用できません。同時に使用された場合、outboundTagのみが有効になります。"
|
||||
|
||||
[pages.xray.wireguard]
|
||||
"secretKey" = "シークレットキー"
|
||||
"publicKey" = "公開鍵"
|
||||
"allowedIPs" = "許可されたIP"
|
||||
"endpoint" = "エンドポイント"
|
||||
"psk" = "共有キー"
|
||||
"domainStrategy" = "ドメイン戦略"
|
||||
|
||||
[pages.xray.dns]
|
||||
"enable" = "DNSを有効にする"
|
||||
"enableDesc" = "組み込みDNSサーバーを有効にする"
|
||||
"tag" = "DNSインバウンドタグ"
|
||||
"tagDesc" = "このタグはルーティングルールでインバウンドタグとして使用できます"
|
||||
"strategy" = "クエリ戦略"
|
||||
"strategyDesc" = "ドメイン名解決の全体的な戦略"
|
||||
"add" = "サーバー追加"
|
||||
"edit" = "サーバー編集"
|
||||
"domains" = "ドメイン"
|
||||
"expectIPs" = "期待されるIP"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "フェイクDNS追加"
|
||||
"edit" = "フェイクDNS編集"
|
||||
"ipPool" = "IPプールサブネット"
|
||||
"poolSize" = "プールサイズ"
|
||||
|
||||
[pages.settings.security]
|
||||
"admin" = "管理者"
|
||||
"secret" = "セキュリティトークン"
|
||||
"loginSecurity" = "ログインセキュリティ"
|
||||
"loginSecurityDesc" = "追加の認証を追加してセキュリティを向上させる"
|
||||
"secretToken" = "セキュリティトークン"
|
||||
"secretTokenDesc" = "このトークンを安全な場所に保管してください。このトークンはログインに使用され、紛失すると回復できません。"
|
||||
|
||||
[pages.settings.toasts]
|
||||
"modifySettings" = "設定を変更"
|
||||
"getSettings" = "設定を取得"
|
||||
"modifyUser" = "管理者を変更"
|
||||
"originalUserPassIncorrect" = "旧ユーザー名または旧パスワードが間違っています"
|
||||
"userPassMustBeNotEmpty" = "新しいユーザー名と新しいパスワードは空にできません"
|
||||
|
||||
[tgbot]
|
||||
"keyboardClosed" = "❌ カスタムキーボードが閉じられました!"
|
||||
"noResult" = "❗ 結果がありません!"
|
||||
"noQuery" = "❌ クエリが見つかりませんでした!もう一度コマンドを使用してください!"
|
||||
"wentWrong" = "❌ 問題が発生しました!"
|
||||
"noIpRecord" = "❗ IP記録がありません!"
|
||||
"noInbounds" = "❗ インバウンド接続が見つかりません!"
|
||||
"unlimited" = "♾ 無制限"
|
||||
"add" = "追加"
|
||||
"month" = "月"
|
||||
"months" = "月"
|
||||
"day" = "日"
|
||||
"days" = "日"
|
||||
"hours" = "時間"
|
||||
"unknown" = "不明"
|
||||
"inbounds" = "インバウンド接続"
|
||||
"clients" = "クライアント"
|
||||
"offline" = "🔴 オフライン"
|
||||
"online" = "🟢 オンライン"
|
||||
|
||||
[tgbot.commands]
|
||||
"unknown" = "❗ 不明なコマンド"
|
||||
"pleaseChoose" = "👇 選択してください:\r\n"
|
||||
"help" = "🤖 このボットをご利用いただきありがとうございます!サーバーから特定のデータを提供し、必要な変更を行うことができます。\r\n\r\n"
|
||||
"start" = "👋 こんにちは、<i>{{ .Firstname }}</i>。\r\n"
|
||||
"welcome" = "🤖 <b>{{ .Hostname }}</b> 管理ボットへようこそ。\r\n"
|
||||
"status" = "✅ ボットは正常に動作しています!"
|
||||
"usage" = "❗ 検索するテキストを入力してください!"
|
||||
"getID" = "🆔 あなたのIDは:<code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Xray Coreを再起動するには:\r\n<code>/restart force</code>\r\n\r\nクライアントの電子メールを検索するには:\r\n<code>/usage [電子メール]</code>\r\n\r\nインバウンド(クライアントの統計情報を含む)を検索するには:\r\n<code>/inbound [備考]</code>\r\n\r\nTelegramチャットID:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "統計情報を検索するには、次のコマンドを使用してください:\r\n<code>/usage [電子メール]</code>\r\n\r\nTelegramチャットID:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ 操作成功!"
|
||||
"restartFailed" = "❗ 操作エラー。\r\n\r\n<code>エラー: {{ .Error }}</code>"
|
||||
"xrayNotRunning" = "❗ Xray Core は動作していません。"
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 CPU使用率は{{ .Percent }}%、しきい値{{ .Threshold }}%を超えました"
|
||||
"selectUserFailed" = "❌ ユーザーの選択に失敗しました!"
|
||||
"userSaved" = "✅ Telegramユーザーが保存されました。"
|
||||
"loginSuccess" = "✅ パネルに正常にログインしました。\r\n"
|
||||
"loginFailed" = "❗️ パネルのログインに失敗しました。\r\n"
|
||||
"report" = "🕰 定期報告:{{ .RunTime }}\r\n"
|
||||
"datetime" = "⏰ 日時:{{ .DateTime }}\r\n"
|
||||
"hostname" = "💻 ホスト名:{{ .Hostname }}\r\n"
|
||||
"version" = "🚀 X-UI バージョン:{{ .Version }}\r\n"
|
||||
"xrayVersion" = "📡 Xray バージョン: {{ .XrayVersion }}\r\n"
|
||||
"ipv6" = "🌐 IPv6:{{ .IPv6 }}\r\n"
|
||||
"ipv4" = "🌐 IPv4:{{ .IPv4 }}\r\n"
|
||||
"ip" = "🌐 IP:{{ .IP }}\r\n"
|
||||
"ips" = "🔢 IPアドレス:\r\n{{ .IPs }}\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"
|
||||
"traffic" = "🚦 トラフィック:{{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
|
||||
"xrayStatus" = "ℹ️ Xrayステータス:{{ .State }}\r\n"
|
||||
"username" = "👤 ユーザー名:{{ .Username }}\r\n"
|
||||
"password" = "👤 パスワード: {{ .Password }}\r\n"
|
||||
"time" = "⏰ 時間:{{ .Time }}\r\n"
|
||||
"inbound" = "📍 インバウンド:{{ .Remark }}\r\n"
|
||||
"port" = "🔌 ポート:{{ .Port }}\r\n"
|
||||
"expire" = "📅 有効期限:{{ .Time }}\r\n"
|
||||
"expireIn" = "📅 残り時間:{{ .Time }}\r\n"
|
||||
"active" = "💡 有効:{{ .Enable }}\r\n"
|
||||
"enabled" = "🚨 有効化済み:{{ .Enable }}\r\n"
|
||||
"online" = "🌐 接続ステータス:{{ .Status }}\r\n"
|
||||
"email" = "📧 メール:{{ .Email }}\r\n"
|
||||
"upload" = "🔼 アップロード↑:{{ .Upload }}\r\n"
|
||||
"download" = "🔽 ダウンロード↓:{{ .Download }}\r\n"
|
||||
"total" = "📊 合計:{{ .UpDown }} / {{ .Total }}\r\n"
|
||||
"TGUser" = "👤 Telegramユーザー:{{ .TelegramID }}\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"
|
||||
"refreshedOn" = "\r\n📋🔄 更新時間:{{ .Time }}\r\n\r\n"
|
||||
"yes" = "✅ はい"
|
||||
"no" = "❌ いいえ"
|
||||
|
||||
[tgbot.buttons]
|
||||
"closeKeyboard" = "❌ キーボードを閉じる"
|
||||
"cancel" = "❌ キャンセル"
|
||||
"cancelReset" = "❌ リセットをキャンセル"
|
||||
"cancelIpLimit" = "❌ IP制限をキャンセル"
|
||||
"confirmResetTraffic" = "✅ トラフィックをリセットしますか?"
|
||||
"confirmClearIps" = "✅ IPをクリアしますか?"
|
||||
"confirmRemoveTGUser" = "✅ Telegramユーザーを削除しますか?"
|
||||
"confirmToggle" = "✅ ユーザーを有効/無効にしますか?"
|
||||
"dbBackup" = "データベースバックアップを取得"
|
||||
"serverUsage" = "サーバーの使用状況"
|
||||
"getInbounds" = "インバウンド情報を取得"
|
||||
"depleteSoon" = "間もなく消耗"
|
||||
"clientUsage" = "使用状況を取得"
|
||||
"onlines" = "オンラインクライアント"
|
||||
"commands" = "コマンド"
|
||||
"refresh" = "🔄 更新"
|
||||
"clearIPs" = "❌ IPをクリア"
|
||||
"removeTGUser" = "❌ Telegramユーザーを削除"
|
||||
"selectTGUser" = "👤 Telegramユーザーを選択"
|
||||
"selectOneTGUser" = "👤 1人のTelegramユーザーを選択:"
|
||||
"resetTraffic" = "📈 トラフィックをリセット"
|
||||
"resetExpire" = "📅 有効期限を変更"
|
||||
"ipLog" = "🔢 IPログ"
|
||||
"ipLimit" = "🔢 IP制限"
|
||||
"setTGUser" = "👤 Telegramユーザーを設定"
|
||||
"toggle" = "🔘 有効/無効"
|
||||
"custom" = "🔢 カスタム"
|
||||
"confirmNumber" = "✅ 確認: {{ .Num }}"
|
||||
"confirmNumberAdd" = "✅ 追加を確認:{{ .Num }}"
|
||||
"limitTraffic" = "🚧 トラフィック制限"
|
||||
"getBanLogs" = "禁止ログ"
|
||||
"allClients" = "すべてのクライアント"
|
||||
|
||||
[tgbot.answers]
|
||||
"successfulOperation" = "✅ 成功!"
|
||||
"errorOperation" = "❗ 操作エラー。"
|
||||
"getInboundsFailed" = "❌ インバウンド情報の取得に失敗しました。"
|
||||
"getClientsFailed" = "❌ クライアントの取得に失敗しました。"
|
||||
"canceled" = "❌ {{ .Email }}:操作がキャンセルされました。"
|
||||
"clientRefreshSuccess" = "✅ {{ .Email }}:クライアントが正常に更新されました。"
|
||||
"IpRefreshSuccess" = "✅ {{ .Email }}:IPが正常に更新されました。"
|
||||
"TGIdRefreshSuccess" = "✅ {{ .Email }}:クライアントのTelegramユーザーが正常に更新されました。"
|
||||
"resetTrafficSuccess" = "✅ {{ .Email }}:トラフィックが正常にリセットされました。"
|
||||
"setTrafficLimitSuccess" = "✅ {{ .Email }}:トラフィック制限が正常に保存されました。"
|
||||
"expireResetSuccess" = "✅ {{ .Email }}:有効期限の日数が正常にリセットされました。"
|
||||
"resetIpSuccess" = "✅ {{ .Email }}:IP制限数が正常に保存されました:{{ .Count }}。"
|
||||
"clearIpSuccess" = "✅ {{ .Email }}:IPが正常にクリアされました。"
|
||||
"getIpLog" = "✅ {{ .Email }}:IPログの取得。"
|
||||
"getUserInfo" = "✅ {{ .Email }}:Telegramユーザー情報の取得。"
|
||||
"removedTGUserSuccess" = "✅ {{ .Email }}:Telegramユーザーが正常に削除されました。"
|
||||
"enableSuccess" = "✅ {{ .Email }}:正常に有効化されました。"
|
||||
"disableSuccess" = "✅ {{ .Email }}:正常に無効化されました。"
|
||||
"askToAddUserId" = "設定が見つかりませんでした!\r\n管理者に問い合わせて、設定にTelegramユーザーのChatIDを使用してください。\r\n\r\nあなたのユーザーChatID:<code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "インバウンド {{ .Inbound }} のクライアントを選択"
|
||||
"chooseInbound" = "インバウンドを選択"
|
||||
@@ -43,8 +43,8 @@
|
||||
"domainName" = "Nome de Domínio"
|
||||
"monitor" = "IP de Escuta"
|
||||
"certificate" = "Certificado Digital"
|
||||
"fail" = " Falhou"
|
||||
"success" = " Com Sucesso"
|
||||
"fail" = "Falhou"
|
||||
"success" = "Com Sucesso"
|
||||
"getVersion" = "Obter Versão"
|
||||
"install" = "Instalar"
|
||||
"clients" = "Clientes"
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Porta de Destino"
|
||||
"targetAddress" = "Endereço de Destino"
|
||||
"monitorDesc" = "Deixe em branco para ouvir todos os IPs"
|
||||
"meansNoLimit" = " = Ilimitado. (unidade: GB)"
|
||||
"meansNoLimit" = "= Ilimitado. (unidade: GB)"
|
||||
"totalFlow" = "Fluxo Total"
|
||||
"leaveBlankToNeverExpire" = "Deixe em branco para nunca expirar"
|
||||
"noRecommendKeepDefault" = "Recomenda-se manter o padrão"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "O histórico de IPs. (para ativar o inbound após a desativação, limpe o log)"
|
||||
"IPLimitlogclear" = "Limpar o Log"
|
||||
"setDefaultCert" = "Definir Certificado pelo Painel"
|
||||
"xtlsDesc" = "O Xray deve ser v1.7.5"
|
||||
"realityDesc" = "O Xray deve ser v1.8.0+"
|
||||
"telegramDesc" = "Por favor, forneça o ID do Chat do Telegram. (use o comando '/id' no bot) ou (@userinfobot)"
|
||||
"subscriptionDesc" = "Para encontrar seu URL de assinatura, navegue até 'Detalhes'. Além disso, você pode usar o mesmo nome para vários clientes."
|
||||
"info" = "Informações"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "O token do bot do Telegram obtido de '@BotFather'."
|
||||
"telegramProxy" = "Proxy SOCKS"
|
||||
"telegramProxyDesc" = "Ativa o proxy SOCKS5 para conectar ao Telegram. (ajuste as configurações conforme o guia)"
|
||||
"telegramAPIServer" = "API Server do Telegram"
|
||||
"telegramAPIServerDesc" = "O servidor API do Telegram a ser usado. Deixe em branco para usar o servidor padrão."
|
||||
"telegramChatId" = "ID de Chat do Administrador"
|
||||
"telegramChatIdDesc" = "O(s) ID(s) de Chat do Administrador no Telegram. (separado por vírgulas)(obtenha aqui @userinfobot) ou (use o comando '/id' no bot)"
|
||||
"telegramNotifyTime" = "Hora da Notificação"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Fragmentação"
|
||||
"fragmentDesc" = "Ativa a fragmentação para o pacote TLS hello."
|
||||
"fragmentSett" = "Configurações de Fragmentação"
|
||||
"noiseDesc" = "Ativar Noise."
|
||||
"noiseSett" = "Configurações de Noise"
|
||||
"noisesDesc" = "Ativar Noises."
|
||||
"noisesSett" = "Configurações de Noises"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Transmitir múltiplos fluxos de dados independentes dentro de um fluxo de dados estabelecido."
|
||||
"muxSett" = "Configurações de Mux"
|
||||
"direct" = "Conexão Direta"
|
||||
"directDesc" = "Estabelece conexões diretamente com domínios ou intervalos de IP de um país específico."
|
||||
"directSett" = "Opções de Conexão Direta"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Configurações Xray"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Os logs podem afetar a eficiência do servidor. É recomendável habilitá-los com sabedoria apenas se necessário."
|
||||
"blockConfigs" = "Escudo de Proteção"
|
||||
"blockConfigsDesc" = "Essas opções bloqueiam tráfego com base em protocolos e sites específicos solicitados."
|
||||
"blockCountryConfigs" = "Bloquear País"
|
||||
"blockCountryConfigsDesc" = "Essas opções bloqueiam tráfego com base no país solicitado."
|
||||
"directCountryConfigs" = "País Direto"
|
||||
"directCountryConfigsDesc" = "Uma conexão direta garante que o tráfego específico não seja roteado por outro servidor."
|
||||
"ipv4Configs" = "Roteamento IPv4"
|
||||
"ipv4ConfigsDesc" = "Essas opções roteam o tráfego para um destino específico via IPv4."
|
||||
"warpConfigs" = "Roteamento WARP"
|
||||
"warpConfigsDesc" = "Essas opções roteam o tráfego para um destino específico via WARP."
|
||||
"basicRouting" = "Roteamento Básico"
|
||||
"blockConnectionsConfigsDesc" = "Essas opções bloquearão o tráfego com base no país solicitado."
|
||||
"directConnectionsConfigsDesc" = "Uma conexão direta garante que o tráfego específico não seja roteado por outro servidor."
|
||||
"blockips" = "Bloquear IPs"
|
||||
"blockdomains" = "Bloquear Domínios"
|
||||
"directips" = "IPs Diretos"
|
||||
"directdomains" = "Domínios Diretos"
|
||||
"ipv4Routing" = "Roteamento IPv4"
|
||||
"ipv4RoutingDesc" = "Essas opções roteam o tráfego para um destino específico via IPv4."
|
||||
"warpRouting" = "Roteamento WARP"
|
||||
"warpRoutingDesc" = "Essas opções roteam o tráfego para um destino específico via WARP."
|
||||
"Template" = "Modelo de Configuração Avançada do Xray"
|
||||
"TemplateDesc" = "O arquivo final de configuração do Xray será gerado com base neste modelo."
|
||||
"FreedomStrategy" = "Estratégia do Protocolo Freedom"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "Definir a estratégia geral de roteamento de tráfego para resolver todas as solicitações."
|
||||
"Torrent" = "Bloquear Protocolo BitTorrent"
|
||||
"TorrentDesc" = "Bloqueia o protocolo BitTorrent."
|
||||
"PrivateIp" = "Bloquear Conexão para IPs Privados"
|
||||
"PrivateIpDesc" = "Bloqueia a conexão com faixas de IP privadas."
|
||||
"Ads" = "Bloquear Anúncios"
|
||||
"AdsDesc" = "Bloqueia sites de publicidade."
|
||||
"Family" = "Proteção Familiar"
|
||||
"FamilyDesc" = "Bloqueia conteúdo adulto e sites maliciosos."
|
||||
"Security" = "Escudo de Segurança"
|
||||
"SecurityDesc" = "Bloqueia sites de malware, phishing e mineradores de criptomoedas."
|
||||
"Speedtest" = "Bloquear Speedtest"
|
||||
"SpeedtestDesc" = "Bloqueia a conexão com sites de teste de velocidade."
|
||||
"IRIp" = "Bloquear Conexão para IPs do Irã"
|
||||
"IRIpDesc" = "Bloqueia a conexão com faixas de IP do Irã."
|
||||
"IRDomain" = "Bloquear Conexão para Domínios do Irã"
|
||||
"IRDomainDesc" = "Bloqueia a conexão com domínios do Irã."
|
||||
"ChinaIp" = "Bloquear Conexão para IPs da China"
|
||||
"ChinaIpDesc" = "Bloqueia a conexão com faixas de IP da China."
|
||||
"ChinaDomain" = "Bloquear Conexão para Domínios da China"
|
||||
"ChinaDomainDesc" = "Bloqueia a conexão com domínios da China."
|
||||
"RussiaIp" = "Bloquear Conexão para IPs da Rússia"
|
||||
"RussiaIpDesc" = "Bloqueia a conexão com faixas de IP da Rússia."
|
||||
"RussiaDomain" = "Bloquear Conexão para Domínios da Rússia"
|
||||
"RussiaDomainDesc" = "Bloqueia a conexão com domínios da Rússia."
|
||||
"VNIp" = "Bloquear Conexão para IPs do Vietnã"
|
||||
"VNIpDesc" = "Bloqueia a conexão com faixas de IP do Vietnã."
|
||||
"VNDomain" = "Bloquear Conexão para Domínios do Vietnã"
|
||||
"VNDomainDesc" = "Bloqueia a conexão com domínios do Vietnã."
|
||||
"DirectIRIp" = "Conexão Direta para IPs do Irã"
|
||||
"DirectIRIpDesc" = "Estabelece conexão diretamente com faixas de IP do Irã."
|
||||
"DirectIRDomain" = "Conexão Direta para Domínios do Irã"
|
||||
"DirectIRDomainDesc" = "Estabelece conexão diretamente com domínios do Irã."
|
||||
"DirectChinaIp" = "Conexão Direta para IPs da China"
|
||||
"DirectChinaIpDesc" = "Estabelece conexão diretamente com faixas de IP da China."
|
||||
"DirectChinaDomain" = "Conexão Direta para Domínios da China"
|
||||
"DirectChinaDomainDesc" = "Estabelece conexão diretamente com domínios da China."
|
||||
"DirectRussiaIp" = "Conexão Direta para IPs da Rússia"
|
||||
"DirectRussiaIpDesc" = "Estabelece conexão diretamente com faixas de IP da Rússia."
|
||||
"DirectRussiaDomain" = "Conexão Direta para Domínios da Rússia"
|
||||
"DirectRussiaDomainDesc" = "Estabelece conexão diretamente com domínios da Rússia."
|
||||
"DirectVNIp" = "Conexão Direta para IPs do Vietnã"
|
||||
"DirectVNIpDesc" = "Estabelece conexão diretamente com faixas de IP do Vietnã."
|
||||
"DirectVNDomain" = "Conexão Direta para Domínios do Vietnã"
|
||||
"DirectVNDomainDesc" = "Estabelece conexão diretamente com domínios do Vietnã."
|
||||
"GoogleIPv4" = "Google"
|
||||
"GoogleIPv4Desc" = "Roteia tráfego para o Google via IPv4."
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "Roteia tráfego para a Netflix via IPv4."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Adiciona roteamento para o Google via WARP."
|
||||
"OpenAIWARP" = "ChatGPT"
|
||||
"OpenAIWARPDesc" = "Roteia tráfego para o ChatGPT via WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Roteia tráfego para a Netflix via WARP."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Roteia tráfego para Meta (Instagram, Facebook, WhatsApp, Threads,...) via WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Roteia tráfego para a Apple via WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Roteia tráfego para o Reddit via WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Roteia tráfego para o Spotify via WARP."
|
||||
"IRWARP" = "Domínios do Irã"
|
||||
"IRWARPDesc" = "Roteia tráfego para domínios do Irã via WARP."
|
||||
"Inbounds" = "Inbounds"
|
||||
"InboundsDesc" = "Aceitar clientes específicos."
|
||||
"Outbounds" = "Outbounds"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "O caminho do arquivo para o log de acesso. O valor especial 'none' desativa os logs de acesso."
|
||||
"errorLog" = "Log de Erros"
|
||||
"errorLogDesc" = "O caminho do arquivo para o log de erros. O valor especial 'none' desativa os logs de erro."
|
||||
"dnsLog" = "Log DNS"
|
||||
"dnsLogDesc" = "Se ativar logs de consulta DNS"
|
||||
"maskAddress" = "Mascarar Endereço"
|
||||
"maskAddressDesc" = "Máscara de endereço IP, quando ativado, substitui automaticamente o endereço IP que aparece no log."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "Primeiro"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Adicionar Servidor"
|
||||
"edit" = "Editar Servidor"
|
||||
"domains" = "Domínios"
|
||||
"expectIPs" = "IPs Esperadas"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Adicionar Fake DNS"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ Bot está OK!"
|
||||
"usage" = "❗ Por favor, forneça um texto para pesquisar!"
|
||||
"getID" = "🆔 Seu ID: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Para pesquisar por um email de cliente:\r\n<code>/usage [Email]</code>\r\n\r\nPara pesquisar por inbounds (com estatísticas do cliente):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "Para reiniciar o Xray Core:\r\n<code>/restart force</code>\r\n\r\nPara pesquisar por um email de cliente:\r\n<code>/usage [Email]</code>\r\n\r\nPara pesquisar por inbounds (com estatísticas do cliente):\r\n<code>/inbound [Remark]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "Para pesquisar por estatísticas, use o seguinte comando:\r\n\r\n<code>/usage [Email]</code>\r\n\r\nTelegram Chat ID:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ Operação bem-sucedida!"
|
||||
"restartFailed" = "❗ Erro na operação.\r\n\r\n<code>Erro: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core não está em execução."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 A carga da CPU {{ .Percent }}% excede o limite de {{ .Threshold }}%"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"username" = "Имя пользователя"
|
||||
"password" = "Пароль"
|
||||
"login" = "Логин"
|
||||
"login" = "Войти"
|
||||
"confirm" = "Подтвердить"
|
||||
"cancel" = "Отмена"
|
||||
"close" = "Закрыть"
|
||||
@@ -67,12 +67,12 @@
|
||||
"settings" = "Настройки панели"
|
||||
"xray" = "Настройки Xray"
|
||||
"logout" = "Выход"
|
||||
"link" = "Менеджмент"
|
||||
"link" = "Управление"
|
||||
|
||||
[pages.login]
|
||||
"hello" = "Привет"
|
||||
"title" = "Добро пожаловать"
|
||||
"loginAgain" = "Время пребывания в сети вышло. Пожалуйста, войдите в систему снова"
|
||||
"loginAgain" = "Ваша сессия истекла. Пожалуйста, войдите в систему снова"
|
||||
|
||||
[pages.login.toasts]
|
||||
"invalidFormData" = "Недопустимый формат данных"
|
||||
@@ -93,8 +93,8 @@
|
||||
"xraySwitchClickDesk" = "Выбирайте внимательно, так как старые версии могут быть несовместимы с текущими конфигурациями"
|
||||
"operationHours" = "Время работы системы"
|
||||
"systemLoad" = "Системная нагрузка"
|
||||
"systemLoadDesc" = "средняя загрузка системы за последние 1, 5 и 15 минут"
|
||||
"connectionTcpCountDesc" = "Всего подключений TCP по всем сетевым картам."
|
||||
"systemLoadDesc" = "Средняя загрузка системы за последние 1, 5 и 15 минут"
|
||||
"connectionTcpCountDesc" = "Общее количество подключений TCP по всем сетевым картам."
|
||||
"connectionUdpCountDesc" = "Общее количество подключений UDP по всем сетевым картам."
|
||||
"connectionCount" = "Количество соединений"
|
||||
"upSpeed" = "Общая скорость upload для всех сетей"
|
||||
@@ -133,21 +133,21 @@
|
||||
"update" = "Обновить"
|
||||
"modifyInbound" = "Изменить подключение"
|
||||
"deleteInbound" = "Удалить подключение"
|
||||
"deleteInboundContent" = "Подтвердите удаление подключения?"
|
||||
"deleteInboundContent" = "Вы уверены, что хотите удалить подключение?"
|
||||
"deleteClient" = "Удалить клиента"
|
||||
"deleteClientContent" = "Вы уверены, что хотите удалить клиента?"
|
||||
"resetTrafficContent" = "Подтвердите сброс трафика?"
|
||||
"resetTrafficContent" = "Вы уверены, что хотите сбросить трафик?"
|
||||
"copyLink" = "Копировать ключ"
|
||||
"address" = "Адрес"
|
||||
"network" = "Сеть"
|
||||
"destinationPort" = "Порт назначения"
|
||||
"targetAddress" = "Целевой адрес"
|
||||
"monitorDesc" = "Оставьте пустым по умолчанию"
|
||||
"meansNoLimit" = " = Без ограничений (значение: ГБ)"
|
||||
"monitorDesc" = "Оставьте пустым для прослушивания всех IP-адресов"
|
||||
"meansNoLimit" = "= Без ограничений (значение: ГБ)"
|
||||
"totalFlow" = "Общий расход"
|
||||
"leaveBlankToNeverExpire" = "Оставьте пустым, чтобы не истекало"
|
||||
"noRecommendKeepDefault" = "Нет требований для сохранения настроек по умолчанию"
|
||||
"certificatePath" = "Путь файла"
|
||||
"noRecommendKeepDefault" = "Не рекомендуется оставлять настройки по умолчанию"
|
||||
"certificatePath" = "Путь к файлу"
|
||||
"certificateContent" = "Содержимое файла"
|
||||
"publicKey" = "Публичный ключ"
|
||||
"privatekey" = "Приватный ключ"
|
||||
@@ -160,16 +160,16 @@
|
||||
"cloneInboundOk" = "Клонировано"
|
||||
"resetAllTraffic" = "Сбросить трафик всех подключений"
|
||||
"resetAllTrafficTitle" = "Сброс трафика всех подключений"
|
||||
"resetAllTrafficContent" = "Подтверждаете сброс трафика всех подключений?"
|
||||
"resetAllTrafficContent" = "Вы уверены, что хотите сбросить трафик всех подключений?"
|
||||
"resetInboundClientTraffics" = "Сбросить трафик пользователей"
|
||||
"resetInboundClientTrafficTitle" = "Сброс трафика пользователей"
|
||||
"resetInboundClientTrafficContent" = "Вы уверены, что хотите сбросить весь трафик для этих пользователей?"
|
||||
"resetAllClientTraffics" = "Сбросить трафик всех пользователей"
|
||||
"resetAllClientTrafficTitle" = "Сброс трафика всех пользователей"
|
||||
"resetAllClientTrafficContent" = "Подтверждаете сброс трафика всех пользователей?"
|
||||
"resetAllClientTrafficContent" = "Вы уверены, что хотите сбросить трафик всех пользователей?"
|
||||
"delDepletedClients" = "Удалить отключенных пользователей"
|
||||
"delDepletedClientsTitle" = "Удаление отключенных пользователей"
|
||||
"delDepletedClientsContent" = "Подтверждаете удаление отключенных пользователей?"
|
||||
"delDepletedClientsContent" = "Вы уверены, что хотите удалить всех отключенных пользователей?"
|
||||
"email" = "Email"
|
||||
"emailDesc" = "Пожалуйста, укажите уникальный Email"
|
||||
"IPLimit" = "Ограничение по IP"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "Лог IP-адресов (перед включением лога IP-адресов, вы должны очистить список)"
|
||||
"IPLimitlogclear" = "Очистить лог"
|
||||
"setDefaultCert" = "Установить сертификат с панели"
|
||||
"xtlsDesc" = "Версия Xray должна быть не ниже 1.7.5"
|
||||
"realityDesc" = "Версия Xray должна быть не ниже 1.8.0"
|
||||
"telegramDesc" = "Пожалуйста, укажите ID чата Telegram. (используйте команду '/id' в боте) или (@userinfobot)"
|
||||
"subscriptionDesc" = "Вы можете найти свою ссылку подписки в разделе 'Подробнее', также вы можете использовать одно и то же имя для нескольких конфигураций"
|
||||
"info" = "Информация"
|
||||
@@ -187,7 +185,7 @@
|
||||
"inboundData" = "Входящие данные"
|
||||
"exportInbound" = "Экспорт входящих"
|
||||
"import" = "Импортировать"
|
||||
"importInbound" = "Импортировать входящее сообщение"
|
||||
"importInbound" = "Импортировать подключение"
|
||||
|
||||
[pages.client]
|
||||
"add" = "Добавить пользователя"
|
||||
@@ -214,13 +212,13 @@
|
||||
"request" = "Запрос"
|
||||
"response" = "Ответ"
|
||||
"name" = "Имя"
|
||||
"value" = "Ценить"
|
||||
"value" = "Значение"
|
||||
|
||||
[pages.inbounds.stream.tcp]
|
||||
"version" = "Версия"
|
||||
"method" = "Метод"
|
||||
"path" = "Путь"
|
||||
"status" = "Положение дел"
|
||||
"status" = "Статус"
|
||||
"statusDescription" = "Описание статуса"
|
||||
"requestHeader" = "Заголовок запроса"
|
||||
"responseHeader" = "Заголовок ответа"
|
||||
@@ -228,9 +226,9 @@
|
||||
[pages.settings]
|
||||
"title" = "Настройки"
|
||||
"save" = "Сохранить"
|
||||
"infoDesc" = "Каждое сделанное здесь изменение необходимо сохранить. Пожалуйста, перезапустите панель, чтобы изменения вступили в силу"
|
||||
"infoDesc" = "Каждое выполненное изменение необходимо сохранить. Пожалуйста, перезапустите панель, чтобы изменения вступили в силу"
|
||||
"restartPanel" = "Перезапуск панели"
|
||||
"restartPanelDesc" = "Подтвердите перезапуск панели? ОК для перезапуска панели через 3 сек. Если вы не можете пользоваться панелью после перезапуска, пожалуйста, посмотрите лог панели на сервере"
|
||||
"restartPanelDesc" = "Вы уверены, что хотите перезапустить панель? Нажмите ОК для перезапуска панели через 3 сек. Если вы не можете пользоваться панелью после перезапуска, пожалуйста, посмотрите лог панели на сервере"
|
||||
"actions" = "Действия"
|
||||
"resetDefaultConfig" = "Сбросить на конфигурацию по умолчанию"
|
||||
"panelSettings" = "Настройки панели"
|
||||
@@ -243,21 +241,21 @@
|
||||
"panelPort" = "Порт панели"
|
||||
"panelPortDesc" = "Порт, используемый для отображения этой панели"
|
||||
"publicKeyPath" = "Путь к файлу публичного ключа сертификата панели"
|
||||
"publicKeyPathDesc" = "Введите полный путь, начинающийся с"
|
||||
"publicKeyPathDesc" = "Введите полный путь, начинающийся с '/'"
|
||||
"privateKeyPath" = "Путь к файлу приватного ключа сертификата панели"
|
||||
"privateKeyPathDesc" = "Введите полный путь, начинающийся с"
|
||||
"privateKeyPathDesc" = "Введите полный путь, начинающийся с '/'"
|
||||
"panelUrlPath" = "Корневой путь URL адреса панели"
|
||||
"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на"
|
||||
"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'"
|
||||
"pageSize" = "Размер нумерации страниц"
|
||||
"pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить"
|
||||
"remarkModel" = "Модель примечания и символ разделения"
|
||||
"datepicker" = "Выбор даты"
|
||||
"datepickerPlaceholder" = "Выберите дату"
|
||||
"datepickerDescription" = "Тип календаря выбора указывает дату истечения срока действия."
|
||||
"datepickerDescription" = "Запланированные задачи выполняются в соответствии с данным календарём"
|
||||
"sampleRemark" = "Пример замечания"
|
||||
"oldUsername" = "Текущее имя пользователя"
|
||||
"oldUsername" = "Текущий логин"
|
||||
"currentPassword" = "Текущий пароль"
|
||||
"newUsername" = "Новое имя пользователя"
|
||||
"newUsername" = "Новый логин"
|
||||
"newPassword" = "Новый пароль"
|
||||
"telegramBotEnable" = "Включить Telegram бота"
|
||||
"telegramBotEnableDesc" = "Подключайтесь к функциям этой панели через Telegram бота"
|
||||
@@ -265,8 +263,10 @@
|
||||
"telegramTokenDesc" = "Необходимо получить токен у менеджера ботов Telegram @botfather"
|
||||
"telegramProxy" = "Прокси Socks5"
|
||||
"telegramProxyDesc" = "Если для подключения к Telegram вам нужен прокси Socks5. Настройте его параметры согласно руководству."
|
||||
"telegramChatId" = "Telegram ChatID админа бота"
|
||||
"telegramChatIdDesc" = "Множественные идентификаторы чата, разделенные запятыми. Чтобы получить свои идентификаторы чатов, используйте @userinfobot или команду '/id' в боте."
|
||||
"telegramAPIServer" = "API-сервер Telegram"
|
||||
"telegramAPIServerDesc" = "Используемый API-сервер Telegram. Оставьте пустым, чтобы использовать сервер по умолчанию."
|
||||
"telegramChatId" = "Идентификатор Telegram администратора бота"
|
||||
"telegramChatIdDesc" = "Один или несколько идентификаторов администратора бота. Чтобы получить идентификатор, используйте @userinfobot или команду '/id' в боте."
|
||||
"telegramNotifyTime" = "Частота уведомлений бота Telegram"
|
||||
"telegramNotifyTimeDesc" = "Используйте формат времени Crontab"
|
||||
"tgNotifyBackup" = "Резервное копирование базы данных"
|
||||
@@ -291,32 +291,32 @@
|
||||
"subPort" = "Порт подписки"
|
||||
"subPortDesc" = "Номер порта для обслуживания службы подписки не должен использоваться на сервере"
|
||||
"subCertPath" = "Путь к файлу открытого ключа сертификата подписки"
|
||||
"subCertPathDesc" = "Введите абсолютный путь, начинающийся с '/'"
|
||||
"subCertPathDesc" = "Введите полный путь, начинающийся с '/'"
|
||||
"subKeyPath" = "Путь к файлу закрытого ключа сертификата подписки"
|
||||
"subKeyPathDesc" = "Введите абсолютный путь, начинающийся с '/'"
|
||||
"subKeyPathDesc" = "Введите полный путь, начинающийся с '/'"
|
||||
"subPath" = "Корневой путь URL-адреса подписки"
|
||||
"subPathDesc" = "Должен начинаться с '/' и заканчиваться на '/'"
|
||||
"subDomain" = "Домен прослушивания"
|
||||
"subDomainDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все домены и IP-адреса"
|
||||
"subUpdates" = "Интервалы обновления подписки"
|
||||
"subUpdatesDesc" = "Часовой интервал между обновлениями в клиентском приложении"
|
||||
"subUpdatesDesc" = "Интервал между обновлениями в клиентском приложении (в часах)"
|
||||
"subEncrypt" = "Шифровать конфиги"
|
||||
"subEncryptDesc" = "Шифровать возвращенные конфиги в подписке"
|
||||
"subShowInfo" = "Показать информацию об использовании"
|
||||
"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации"
|
||||
"subShowInfoDesc" = "Показывать оставшиеся трафик и дату после имени конфигурации"
|
||||
"subURI" = "URI обратного прокси"
|
||||
"subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами"
|
||||
"fragment" = "Фрагментация"
|
||||
"fragmentDesc" = "Включить фрагментацию для пакета приветствия TLS"
|
||||
"fragmentSett" = "Настройки фрагментации"
|
||||
"noiseDesc" = "Включить Noise."
|
||||
"noiseSett" = "Настройки Noise"
|
||||
"noisesDesc" = "Включить Noises."
|
||||
"noisesSett" = "Настройки Noises"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Передача нескольких независимых потоков данных в рамках установленного потока данных."
|
||||
"muxSett" = "Mux Настройки"
|
||||
"direct" = "Прямая связь"
|
||||
"directDesc" = "Напрямую устанавливает соединения с доменами или диапазонами IP конкретной страны."
|
||||
"directSett" = "Варианты прямого подключения"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Настройки Xray"
|
||||
@@ -327,87 +327,30 @@
|
||||
"generalConfigs" = "Основные настройки"
|
||||
"generalConfigsDesc" = "Эти параметры описывают общие настройки"
|
||||
"logConfigs" = "Журнал"
|
||||
"logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их с умом только в случае ваших нужд!"
|
||||
"logConfigsDesc" = "Журналы могут повлиять на эффективность вашего сервера. Рекомендуется включать их только в случае необходимости!"
|
||||
"blockConfigs" = "Блокировка конфигураций"
|
||||
"blockConfigsDesc" = "Эти параметры не позволят пользователям подключаться к определенным протоколам и веб-сайтам"
|
||||
"blockCountryConfigs" = "Конфигурации блокировки страны"
|
||||
"blockCountryConfigsDesc" = "Эти параметры не позволят пользователям подключаться к доменам определенной страны"
|
||||
"directCountryConfigs" = "Настройки прямого подключения для страны"
|
||||
"directCountryConfigsDesc" = "Прямое подключение обеспечивает, что конкретный трафик не направляется через другой сервер."
|
||||
"ipv4Configs" = "Настройки IPv4"
|
||||
"ipv4ConfigsDesc" = "Эти параметры позволят пользователям маршрутизироваться к целевым доменам только через IPv4"
|
||||
"warpConfigs" = "Настройки WARP"
|
||||
"warpConfigsDesc" = "Внимание: перед использованием этих параметров установите WARP в режиме прокси-сервера socks5 на свой сервер, следуя инструкциям на GitHub панели. WARP будет направлять трафик на веб-сайты через серверы Cloudflare"
|
||||
"basicRouting" = "Базовые соединения"
|
||||
"blockConnectionsConfigsDesc" = "Эти параметры будут блокировать трафик в зависимости от запрашиваемой страны."
|
||||
"directConnectionsConfigsDesc" = "Прямое соединение гарантирует, что определенный трафик не будет перенаправлен через другой сервер."
|
||||
"blockips" = "Блокировать IP"
|
||||
"blockdomains" = "Блокировать домены"
|
||||
"directips" = "Прямые IP"
|
||||
"directdomains" = "Прямые домены"
|
||||
"ipv4Routing" = "Правила IPv4"
|
||||
"ipv4RoutingDesc" = "Эти параметры позволят пользователям маршрутизироваться к целевым доменам только через IPv4"
|
||||
"warpRouting" = "Правила WARP"
|
||||
"warpRoutingDesc" = "Внимание: перед использованием этих параметров установите WARP в режиме прокси-сервера socks5 на свой сервер, следуя инструкциям на GitHub панели. WARP будет направлять трафик на веб-сайты через серверы Cloudflare"
|
||||
"Template" = "Шаблон конфигурации Xray"
|
||||
"TemplateDesc" = "Создание файла конфигурации Xray на основе этого шаблона"
|
||||
"FreedomStrategy" = "Настройка стратегии протокола Freedom"
|
||||
"FreedomStrategyDesc" = "Установка стратегию вывода сети в протоколе Freedom"
|
||||
"FreedomStrategyDesc" = "Установка стратегии вывода сети в протоколе Freedom"
|
||||
"RoutingStrategy" = "Настройка стратегии маршрутизации доменов"
|
||||
"RoutingStrategyDesc" = "Установка общей стратегии маршрутизации разрешения DNS"
|
||||
"Torrent" = "Запрет использования BitTorrent"
|
||||
"TorrentDesc" = "Изменение шаблона конфигурации для предупреждения использования BitTorrent пользователями"
|
||||
"PrivateIp" = "Запрет частных диапазонов IP-адресов для подключения"
|
||||
"PrivateIpDesc" = "Изменение шаблона конфигурации для предупреждения подключения к диапазонам частных IP-адресов"
|
||||
"Ads" = "Блокировка рекламы"
|
||||
"AdsDesc" = "Изменение конфигурации для блокировки рекламы"
|
||||
"Family" = "Блокируйте вредоносное ПО и контент для взрослых"
|
||||
"FamilyDesc" = "DNS-преобразователи Cloudflare для блокировки вредоносного ПО и контента для взрослых в целях защиты семьи."
|
||||
"Security" = "Блокируйте вредоносное ПО, фишинговые сайты и сайты криптомайнеров"
|
||||
"SecurityDesc" = "Изменение шаблона конфигурации для защиты безопасности."
|
||||
"Speedtest" = "Блокировать сайты для проверки скорости"
|
||||
"SpeedtestDesc" = "Изменение шаблона конфигурации для предупреждения подключения к веб-сайтам для тестирования скорости"
|
||||
"IRIp" = "Заблокировать подключения к диапазонам IP-адресов Ирана"
|
||||
"IRIpDesc" = "Изменение конфигурации, чтобы заблокировать подключения к диапазонам IP-адресов Ирана"
|
||||
"IRDomain" = "Заблокировать подключения к доменам Ирана"
|
||||
"IRDomainDesc" = "Изменение конфигурации, чтобы заблокировать подключения к доменам Ирана"
|
||||
"ChinaIp" = "Заблокировать подключения к диапазонам IP-адресов Китая"
|
||||
"ChinaIpDesc" = "Изменение конфигурации, чтобы заблокировать подключения к диапазонам IP-адресов Китая"
|
||||
"ChinaDomain" = "Заблокировать подключения к доменам Китая"
|
||||
"ChinaDomainDesc" = "Изменение конфигурации, чтобы заблокировать подключения к доменам Китая"
|
||||
"RussiaIp" = "Заблокировать подключения к диапазонам IP-адресов России"
|
||||
"RussiaIpDesc" = "Изменение конфигурации, чтобы заблокировать подключения к диапазонами IP-адресов России"
|
||||
"RussiaDomain" = "Заблокировать подключения к доменам России"
|
||||
"RussiaDomainDesc" = "Изменение конфигурации, чтобы заблокировать подключения к доменам России"
|
||||
"VNIp" = "Отключить подключение к IP-адресам Вьетнама"
|
||||
"VNIpDesc" = "Измените шаблон конфигурации, чтобы избежать подключения к диапазонам IP-адресов Вьетнама"
|
||||
"VNDomain" = "Отключить подключение к доменам Вьетнама"
|
||||
"VNDomainDesc" = "Измените шаблон конфигурации, чтобы избежать подключения к доменам Вьетнама."
|
||||
"DirectIRIp" = "Прямое подключения к диапазонам IP-адресов Ирана"
|
||||
"DirectIRIpDesc" = "Изменение шаблона конфигурации для прямого подключения к диапазонам IP-адресов Ирана"
|
||||
"DirectIRDomain" = "Прямое подключение к доменам Ирана"
|
||||
"DirectIRDomainDesc" = "Изменение шаблон конфигурации для прямого подключения к доменам Ирана"
|
||||
"DirectChinaIp" = "Прямое подключение к диапазонам IP-адресов Китая"
|
||||
"DirectChinaIpDesc" = "Изменение шаблона конфигурации для прямого подключения к диапазонам IP-адресов Китая"
|
||||
"DirectChinaDomain" = "Прямое подключение к доменам Китая"
|
||||
"DirectChinaDomainDesc" = "Изменение шаблона конфигурации для прямого подключения к доменам Китая"
|
||||
"DirectRussiaIp" = "Прямое подключение к диапазонам IP-адресов России"
|
||||
"DirectRussiaIpDesc" = "Изменение шаблона конфигурации для прямого подключения к диапазонам IP-адресов России"
|
||||
"DirectRussiaDomain" = "Прямое подключение к доменам России"
|
||||
"DirectRussiaDomainDesc" = "Изменение шаблона конфигурации для прямого подключения к доменам России"
|
||||
"DirectVNIp" = "Прямое подключение к IP-адресам Вьетнама"
|
||||
"DirectVNIpDesc" = "Измените шаблон конфигурации для прямого подключения к диапазонам IP-адресов Вьетнама"
|
||||
"DirectVNDomain" = "Прямое подключение к доменам Вьетнама"
|
||||
"DirectVNDomainDesc" = "Измените шаблон конфигурации для прямого подключения к доменам Вьетнама"
|
||||
"GoogleIPv4" = "Использовать IPv4 для Google"
|
||||
"GoogleIPv4Desc" = "Добавить маршрутизацию для Google для подключения к IPv4"
|
||||
"NetflixIPv4" = "Использовать IPv4 для Netflix"
|
||||
"NetflixIPv4Desc" = "Добавить маршрутизацию для Netflix для подключения к IPv4"
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Направляет трафик в Google через WARP."
|
||||
"OpenAIWARP" = "OpenAI (ChatGPT)"
|
||||
"OpenAIWARPDesc" = "Направляет трафик в OpenAI (ChatGPT) через WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Направляет трафик в Netflix через WARP."
|
||||
"MetaWARP" = "Мета"
|
||||
"MetaWARPDesc" = "Направляет трафик в Meta (Instagram, Facebook, WhatsApp, Threads...) через WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Направляет трафик в Apple через WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Направляет трафик в Reddit через WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Направляет трафик в Spotify через WARP."
|
||||
"IRWARP" = "Маршрутизация доменов Ирана через WARP"
|
||||
"IRWARPDesc" = "Добавить маршрутизацию для доменов Ирана через WARP"
|
||||
"Inbounds" = "Входящие"
|
||||
"InboundsDesc" = "Изменение шаблона конфигурации для подключения определенных пользователей"
|
||||
"Outbounds" = "Исходящие"
|
||||
@@ -419,9 +362,13 @@
|
||||
"logLevel" = "Уровень журнала"
|
||||
"logLevelDesc" = "Уровень журнала для журналов ошибок, указывающий информацию, которую необходимо записать."
|
||||
"accessLog" = "Журнал доступа"
|
||||
"accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключило журналы доступа."
|
||||
"accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключает журналы доступа."
|
||||
"errorLog" = "Журнал ошибок"
|
||||
"errorLogDesc" = "Путь к файлу журнала ошибок. Специальное значение «none» отключает журналы ошибок."
|
||||
"dnsLog" = "DNS Журнал"
|
||||
"dnsLogDesc" = "Включить логи запросов DNS"
|
||||
"maskAddress" = "Маскировать Адрес"
|
||||
"maskAddressDesc" = "Маска IP-адреса, при активации автоматически заменяет IP-адрес, который появляется в логе."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "Первый"
|
||||
@@ -432,7 +379,7 @@
|
||||
"dest" = "Пункт назначения"
|
||||
"inbound" = "Входящий"
|
||||
"outbound" = "Исходящий"
|
||||
"balancer" = "балансир"
|
||||
"balancer" = "Балансировщик"
|
||||
"info" = "Информация"
|
||||
"add" = "Добавить правило"
|
||||
"edit" = "Редактировать правило"
|
||||
@@ -444,7 +391,7 @@
|
||||
"editOutbound" = "Изменить исходящий"
|
||||
"editReverse" = "Редактировать реверс"
|
||||
"tag" = "Тег"
|
||||
"tagDesc" = "уникальный тег"
|
||||
"tagDesc" = "Уникальный тег"
|
||||
"address" = "Адрес"
|
||||
"reverse" = "Обратный"
|
||||
"domain" = "Домен"
|
||||
@@ -453,21 +400,21 @@
|
||||
"portal" = "Портал"
|
||||
"intercon" = "Соединение"
|
||||
"settings" = "Настройки"
|
||||
"accountInfo" = "Информация Об Учетной Записи"
|
||||
"accountInfo" = "Информация об учетной записи"
|
||||
"outboundStatus" = "Исходящий статус"
|
||||
"sendThrough" = "Отправить через"
|
||||
|
||||
[pages.xray.balancer]
|
||||
"addBalancer" = "Добавить балансир"
|
||||
"editBalancer" = "Редактировать балансир"
|
||||
"addBalancer" = "Добавить балансировщик"
|
||||
"editBalancer" = "Редактировать балансировщик"
|
||||
"balancerStrategy" = "Стратегия"
|
||||
"balancerSelectors" = "Селекторы"
|
||||
"tag" = "Тег"
|
||||
"tagDesc" = "уникальный тег"
|
||||
"tagDesc" = "Уникальный тег"
|
||||
"balancerDesc" = "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag."
|
||||
|
||||
[pages.xray.wireguard]
|
||||
"secretKey" = "Секретный ключ"
|
||||
"secretKey" = "Приватный ключ"
|
||||
"publicKey" = "Публичный ключ"
|
||||
"allowedIPs" = "Разрешенные IP-адреса"
|
||||
"endpoint" = "Конечная точка"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Добавить сервер"
|
||||
"edit" = "Редактировать сервер"
|
||||
"domains" = "Домены"
|
||||
"expectIPs" = "Ожидаемые IP"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Добавить поддельный DNS"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ Бот работает нормально!"
|
||||
"usage" = "❗ Пожалуйста, укажите текст для поиска!"
|
||||
"getID" = "🆔 Ваш ID: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Для поиска электронной почты клиента:\r\n<code>/usage [Email]</code>\r\n\r\nДля поиска входящих (со статистикой клиента):\r\n<code>/inbound [Примечание]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "Для перезапуска Xray Core:\r\n<code>/restart force</code>\r\n\r\nДля поиска электронной почты клиента:\r\n<code>/usage [Email]</code>\r\n\r\nДля поиска входящих (со статистикой клиента):\r\n<code>/inbound [Примечание]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "Для поиска статистики используйте следующую команду:\r\n<code>/usage [Email]</code>\r\n\r\nID чата Telegram:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ Операция успешно завершена!"
|
||||
"restartFailed" = "❗ Ошибка в операции.\r\n\r\n<code>Ошибка: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core не запущен."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%"
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Hedef Port"
|
||||
"targetAddress" = "Hedef Adres"
|
||||
"monitorDesc" = "Tüm IP'leri dinlemek için boş bırakın"
|
||||
"meansNoLimit" = " = Sınırsız. (birim: GB)"
|
||||
"meansNoLimit" = "= Sınırsız. (birim: GB)"
|
||||
"totalFlow" = "Toplam Akış"
|
||||
"leaveBlankToNeverExpire" = "Hiçbir zaman sona ermemesi için boş bırakın"
|
||||
"noRecommendKeepDefault" = "Varsayılanı korumanız önerilir"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "IP geçmiş günlüğü. (devre dışı bırakıldıktan sonra gelini etkinleştirmek için günlüğü temizleyin)"
|
||||
"IPLimitlogclear" = "Günlüğü Temizle"
|
||||
"setDefaultCert" = "Panelden Sertifikayı Ayarla"
|
||||
"xtlsDesc" = "Xray v1.7.5 olmalıdır"
|
||||
"realityDesc" = "Xray v1.8.0+ olmalıdır"
|
||||
"telegramDesc" = "Lütfen Telegram Sohbet Kimliği sağlayın. (botta '/id' komutunu kullanın) veya (@userinfobot)"
|
||||
"subscriptionDesc" = "Abonelik URL'inizi bulmak için 'Detaylar'a gidin. Ayrıca, aynı adı birden fazla müşteri için kullanabilirsiniz."
|
||||
"info" = "Bilgi"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "'@BotFather'dan alınan Telegram bot token."
|
||||
"telegramProxy" = "SOCKS Proxy"
|
||||
"telegramProxyDesc" = "Telegram'a bağlanmak için SOCKS5 proxy'sini etkinleştirir. (ayarları kılavuzda belirtilen şekilde ayarlayın)"
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
"telegramAPIServerDesc" = "Kullanılacak Telegram API sunucusu. Varsayılan sunucuyu kullanmak için boş bırakın."
|
||||
"telegramChatId" = "Yönetici Sohbet Kimliği"
|
||||
"telegramChatIdDesc" = "Telegram Yönetici Sohbet Kimliği(leri). (virgülle ayrılmış)(buradan alın @userinfobot) veya (botta '/id' komutunu kullanın)"
|
||||
"telegramNotifyTime" = "Bildirim Zamanı"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Parçalama"
|
||||
"fragmentDesc" = "TLS merhaba paketinin parçalanmasını etkinleştir."
|
||||
"fragmentSett" = "Parçalama Ayarları"
|
||||
"noiseDesc" = "Noise'i Etkinleştir."
|
||||
"noiseSett" = "Noise Ayarları"
|
||||
"noisesDesc" = "Noises'i Etkinleştir."
|
||||
"noisesSett" = "Noises Ayarları"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Kurulmuş bir veri akışında birden çok bağımsız veri akışını iletir."
|
||||
"muxSett" = "Mux Ayarları"
|
||||
"direct" = "Doğrudan Bağlantı"
|
||||
"directDesc" = "Belirli bir ülkenin alan adları veya IP aralıkları ile doğrudan bağlantı kurar."
|
||||
"directSett" = "Doğrudan Bağlantı Seçenekleri"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray Yapılandırmaları"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Günlükler sunucunuzun verimliliğini etkileyebilir. Yalnızca ihtiyaç durumunda akıllıca etkinleştirmeniz önerilir"
|
||||
"blockConfigs" = "Koruma Kalkanı"
|
||||
"blockConfigsDesc" = "Bu seçenekler belirli istek protokolleri ve web siteleri temelinde trafiği engeller."
|
||||
"blockCountryConfigs" = "Ülke Engelleme"
|
||||
"blockCountryConfigsDesc" = "Bu seçenekler belirli istek ülkesi temelinde trafiği engeller."
|
||||
"directCountryConfigs" = "Doğrudan Ülke"
|
||||
"directCountryConfigsDesc" = "Doğrudan bağlantı, belirli trafiğin başka bir sunucu üzerinden yönlendirilmemesini sağlar."
|
||||
"ipv4Configs" = "IPv4 Yönlendirme"
|
||||
"ipv4ConfigsDesc" = "Bu seçenekler belirli bir varış yerine IPv4 üzerinden trafiği yönlendirir."
|
||||
"warpConfigs" = "WARP Yönlendirme"
|
||||
"warpConfigsDesc" = "Bu seçenekler belirli bir varış yerine WARP üzerinden trafiği yönlendirir."
|
||||
"basicRouting" = "Temel Yönlendirme"
|
||||
"blockConnectionsConfigsDesc" = "Bu seçenekler belirli bir istenen ülkeye göre trafiği engelleyecektir."
|
||||
"directConnectionsConfigsDesc" = "Doğrudan bağlantı, belirli bir trafiğin başka bir sunucu üzerinden yönlendirilmediğini sağlar."
|
||||
"blockips" = "IP'leri Engelle"
|
||||
"blockdomains" = "Alan Adlarını Engelle"
|
||||
"directips" = "Doğrudan IP'ler"
|
||||
"directdomains" = "Doğrudan Alan Adları"
|
||||
"ipv4Routing" = "IPv4 Yönlendirme"
|
||||
"ipv4RoutingDesc" = "Bu seçenekler belirli bir varış yerine IPv4 üzerinden trafiği yönlendirir."
|
||||
"warpRouting" = "WARP Yönlendirme"
|
||||
"warpRoutingDesc" = "Bu seçenekler belirli bir varış yerine WARP üzerinden trafiği yönlendirir."
|
||||
"Template" = "Gelişmiş Xray Yapılandırma Şablonu"
|
||||
"TemplateDesc" = "Nihai Xray yapılandırma dosyası bu şablona göre oluşturulacaktır."
|
||||
"FreedomStrategy" = "Freedom Protokol Stratejisi"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "Tüm istekleri çözmek için genel trafik yönlendirme stratejisini ayarlayın."
|
||||
"Torrent" = "BitTorrent Protokolünü Engelle"
|
||||
"TorrentDesc" = "BitTorrent protokolünü engeller."
|
||||
"PrivateIp" = "Özel IP'lere Bağlantıyı Engelle"
|
||||
"PrivateIpDesc" = "Özel IP aralıklarına bağlantı kurmayı engeller."
|
||||
"Ads" = "Reklamları Engelle"
|
||||
"AdsDesc" = "Reklam web sitelerini engeller."
|
||||
"Family" = "Aile Koruması"
|
||||
"FamilyDesc" = "Yetişkin içerikli ve kötü amaçlı yazılım web sitelerini engeller."
|
||||
"Security" = "Güvenlik Kalkanı"
|
||||
"SecurityDesc" = "Kötü amaçlı yazılım, kimlik avı ve kripto madencilik web sitelerini engeller."
|
||||
"Speedtest" = "Speedtest Bağlantısını Engelle"
|
||||
"SpeedtestDesc" = "Speedtest web sitelerine bağlantı kurmayı engeller."
|
||||
"IRIp" = "İran IP'lerine Bağlantıyı Engelle"
|
||||
"IRIpDesc" = "İran IP aralıklarına bağlantı kurmayı engeller."
|
||||
"IRDomain" = "İran Alan Adlarına Bağlantıyı Engelle"
|
||||
"IRDomainDesc" = "İran alan adlarına bağlantı kurmayı engeller."
|
||||
"ChinaIp" = "Çin IP'lerine Bağlantıyı Engelle"
|
||||
"ChinaIpDesc" = "Çin IP aralıklarına bağlantı kurmayı engeller."
|
||||
"ChinaDomain" = "Çin Alan Adlarına Bağlantıyı Engelle"
|
||||
"ChinaDomainDesc" = "Çin alan adlarına bağlantı kurmayı engeller."
|
||||
"RussiaIp" = "Rusya IP'lerine Bağlantıyı Engelle"
|
||||
"RussiaIpDesc" = "Rusya IP aralıklarına bağlantı kurmayı engeller."
|
||||
"RussiaDomain" = "Rusya Alan Adlarına Bağlantıyı Engelle"
|
||||
"RussiaDomainDesc" = "Rusya alan adlarına bağlantı kurmayı engeller."
|
||||
"VNIp" = "Vietnam IP'lerine Bağlantıyı Engelle"
|
||||
"VNIpDesc" = "Vietnam IP aralıklarına bağlantı kurmayı engeller."
|
||||
"VNDomain" = "Vietnam Alan Adlarına Bağlantıyı Engelle"
|
||||
"VNDomainDesc" = "Vietnam alan adlarına bağlantı kurmayı engeller."
|
||||
"DirectIRIp" = "İran IP'lerine Doğrudan Bağlantı"
|
||||
"DirectIRIpDesc" = "İran IP aralıklarına doğrudan bağlantı kurar."
|
||||
"DirectIRDomain" = "İran Alan Adlarına Doğrudan Bağlantı"
|
||||
"DirectIRDomainDesc" = "İran alan adlarına doğrudan bağlantı kurar."
|
||||
"DirectChinaIp" = "Çin IP'lerine Doğrudan Bağlantı"
|
||||
"DirectChinaIpDesc" = "Çin IP aralıklarına doğrudan bağlantı kurar."
|
||||
"DirectChinaDomain" = "Çin Alan Adlarına Doğrudan Bağlantı"
|
||||
"DirectChinaDomainDesc" = "Çin alan adlarına doğrudan bağlantı kurar."
|
||||
"DirectRussiaIp" = "Rusya IP'lerine Doğrudan Bağlantı"
|
||||
"DirectRussiaIpDesc" = "Rusya IP aralıklarına doğrudan bağlantı kurar."
|
||||
"DirectRussiaDomain" = "Rusya Alan Adlarına Doğrudan Bağlantı"
|
||||
"DirectRussiaDomainDesc" = "Rusya alan adlarına doğrudan bağlantı kurar."
|
||||
"DirectVNIp" = "Vietnam IP'lerine Doğrudan Bağlantı"
|
||||
"DirectVNIpDesc" = "Vietnam IP aralıklarına doğrudan bağlantı kurar."
|
||||
"DirectVNDomain" = "Vietnam Alan Adlarına Doğrudan Bağlantı"
|
||||
"DirectVNDomainDesc" = "Vietnam alan adlarına doğrudan bağlantı kurar."
|
||||
"GoogleIPv4" = "Google"
|
||||
"GoogleIPv4Desc" = "Google'a trafiği IPv4 üzerinden yönlendirir."
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "Netflix'e trafiği IPv4 üzerinden yönlendirir."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Google'a trafiği WARP üzerinden yönlendirir."
|
||||
"OpenAIWARP" = "ChatGPT"
|
||||
"OpenAIWARPDesc" = "ChatGPT'ye trafiği WARP üzerinden yönlendirir."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Netflix'e trafiği WARP üzerinden yönlendirir."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Meta'ya (Instagram, Facebook, WhatsApp, Threads,...) trafiği WARP üzerinden yönlendirir."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Apple'a trafiği WARP üzerinden yönlendirir."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Reddit'e trafiği WARP üzerinden yönlendirir."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Spotify'a trafiği WARP üzerinden yönlendirir."
|
||||
"IRWARP" = "İran alan adları"
|
||||
"IRWARPDesc" = "İran alan adlarına trafiği WARP üzerinden yönlendirir."
|
||||
"Inbounds" = "Gelenler"
|
||||
"InboundsDesc" = "Belirli müşterileri kabul eder."
|
||||
"Outbounds" = "Gidenler"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "Erişim günlüğü için dosya yolu. 'none' özel değeri erişim günlüklerini devre dışı bırakır"
|
||||
"errorLog" = "Hata Günlüğü"
|
||||
"errorLogDesc" = "Hata günlüğü için dosya yolu. 'none' özel değeri hata günlüklerini devre dışı bırakır"
|
||||
"dnsLog" = "DNS Günlüğü"
|
||||
"dnsLogDesc" = "DNS sorgu günlüklerini etkinleştirin"
|
||||
"maskAddress" = "Adres Maskesi"
|
||||
"maskAddressDesc" = "IP adresi maskesi, etkinleştirildiğinde, günlükte görünen IP adresini otomatik olarak değiştirecektir."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "İlk"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Sunucu Ekle"
|
||||
"edit" = "Sunucuyu Düzenle"
|
||||
"domains" = "Alan Adları"
|
||||
"expectIPs" = "Beklenen IP'ler"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Sahte DNS Ekle"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ Bot çalışıyor!"
|
||||
"usage" = "❗ Lütfen aramak için bir metin sağlayın!"
|
||||
"getID" = "🆔 Kimliğiniz: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Bir müşteri e-postasını aramak için:\r\n<code>/usage [E-posta]</code>\r\n\r\nGelenleri aramak için (müşteri istatistikleri ile):\r\n<code>/inbound [Açıklama]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "Xray Core'u yeniden başlatmak için:\r\n<code>/restart force</code>\r\n\r\nBir müşteri e-postasını aramak için:\r\n<code>/usage [E-posta]</code>\r\n\r\nGelenleri aramak için (müşteri istatistikleri ile):\r\n<code>/inbound [Açıklama]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "İstatistikleri aramak için şu komutu kullanın:\r\n\r\n<code>/usage [E-posta]</code>\r\n\r\nTelegram Sohbet Kimliği:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ İşlem başarılı!"
|
||||
"restartFailed" = "❗ İşlem hatası.\r\n\r\n<code>Hata: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core çalışmıyor."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 CPU Yükü {{ .Percent }}% eşiği {{ .Threshold }}%'yi aşıyor"
|
||||
@@ -640,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }}: Başarıyla devre dışı bırakıldı."
|
||||
"askToAddUserId" = "Yapılandırmanız bulunamadı!\r\nLütfen yöneticinizden yapılandırmalarınıza Telegram ChatID'nizi eklemesini isteyin.\r\n\r\nKullanıcı ChatID'niz: <code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "Gelen {{ .Inbound }} için bir Müşteri Seçin"
|
||||
"chooseInbound" = "Bir Gelen Seçin"
|
||||
"chooseInbound" = "Bir Gelen Seçin"
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
"domainName" = "Доменне ім`я"
|
||||
"monitor" = "Слухати IP"
|
||||
"certificate" = "Цифровий сертифікат"
|
||||
"fail" = " Помилка"
|
||||
"success" = " Успішно"
|
||||
"fail" = "Помилка"
|
||||
"success" = "Успішно"
|
||||
"getVersion" = "Отримати версію"
|
||||
"install" = "Встановити"
|
||||
"clients" = "Клієнти"
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Порт призначення"
|
||||
"targetAddress" = "Цільова адреса"
|
||||
"monitorDesc" = "Залиште порожнім, щоб слухати всі IP-адреси"
|
||||
"meansNoLimit" = " = Необмежено. (одиниця: ГБ)"
|
||||
"meansNoLimit" = "= Необмежено. (одиниця: ГБ)"
|
||||
"totalFlow" = "Загальна витрата"
|
||||
"leaveBlankToNeverExpire" = "Залиште порожнім, щоб ніколи не закінчувався"
|
||||
"noRecommendKeepDefault" = "Рекомендується зберегти значення за замовчуванням"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "Журнал історії IP-адрес. (щоб увімкнути вхідну після вимкнення, очистіть журнал)"
|
||||
"IPLimitlogclear" = "Очистити журнал"
|
||||
"setDefaultCert" = "Установити сертифікат з панелі"
|
||||
"xtlsDesc" = "Xray має бути v1.7.5"
|
||||
"realityDesc" = "Xray має бути v1.8.0+"
|
||||
"telegramDesc" = "Будь ласка, вкажіть ID чату Telegram. (використовуйте команду '/id' у боті) або (@userinfobot)"
|
||||
"subscriptionDesc" = "Щоб знайти URL-адресу вашої підписки, перейдіть до «Деталі». Крім того, ви можете використовувати одне ім'я для кількох клієнтів."
|
||||
"info" = "Інформація"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "Токен бота Telegram, отриманий від '@BotFather'."
|
||||
"telegramProxy" = "SOCKS Проксі"
|
||||
"telegramProxyDesc" = "Вмикає проксі-сервер SOCKS5 для підключення до Telegram. (відкоригуйте параметри відповідно до посібника)"
|
||||
"telegramAPIServer" = "Сервер Telegram API"
|
||||
"telegramAPIServerDesc" = "Сервер Telegram API для використання. Залиште поле порожнім, щоб використовувати сервер за умовчанням."
|
||||
"telegramChatId" = "Ідентифікатор чату адміністратора"
|
||||
"telegramChatIdDesc" = "Ідентифікатори чату адміністратора Telegram. (розділені комами) (отримайте тут @userinfobot) або (використовуйте команду '/id' у боті)"
|
||||
"telegramNotifyTime" = "Час сповіщення"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Фрагментація"
|
||||
"fragmentDesc" = "Увімкнути фрагментацію для пакету привітання TLS"
|
||||
"fragmentSett" = "Параметри фрагментації"
|
||||
"noiseDesc" = "Увімкнути Noise."
|
||||
"noiseSett" = "Налаштування Noise"
|
||||
"noisesDesc" = "Увімкнути Noises."
|
||||
"noisesSett" = "Налаштування Noises"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Передавати кілька незалежних потоків даних у межах встановленого потоку даних."
|
||||
"muxSett" = "Налаштування Mux"
|
||||
"direct" = "Пряме підключення"
|
||||
"directDesc" = "Безпосередньо встановлює з’єднання з доменами або діапазонами IP певної країни."
|
||||
"directSett" = "Параметри прямого підключення"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray конфігурації"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Журнали можуть вплинути на ефективність вашого сервера. Рекомендується вмикати його з розумом лише у випадку ваших потреб"
|
||||
"blockConfigs" = "Захисний екран"
|
||||
"blockConfigsDesc" = "Ці параметри блокуватимуть трафік на основі конкретних запитуваних протоколів і веб-сайтів."
|
||||
"blockCountryConfigs" = "Заблокувати країну"
|
||||
"blockCountryConfigsDesc" = "Ці параметри блокуватимуть трафік на основі конкретної запитуваної країни."
|
||||
"directCountryConfigs" = "Пряма країна"
|
||||
"directCountryConfigsDesc" = "Пряме підключення забезпечує, що конкретний трафік не маршрутизується через інший сервер."
|
||||
"ipv4Configs" = "Маршрутизація IPv4"
|
||||
"ipv4ConfigsDesc" = "Ці параметри спрямовуватимуть трафік на основі певного призначення через IPv4."
|
||||
"warpConfigs" = "WARP маршрутизація"
|
||||
"warpConfigsDesc" = "Ці параметри маршрутизуватимуть трафік на основі певного пункту призначення через WARP."
|
||||
"basicRouting" = "Основна Маршрутизація"
|
||||
"blockConnectionsConfigsDesc" = "Ці параметри блокуватимуть трафік на основі запитаних країн."
|
||||
"directConnectionsConfigsDesc" = "Пряме з'єднання гарантує, що певний трафік не буде маршрутизовано через інший сервер."
|
||||
"blockips" = "Блокувати IP"
|
||||
"blockdomains" = "Блокувати домени"
|
||||
"directips" = "Прямі IP"
|
||||
"directdomains" = "Прямі домени"
|
||||
"ipv4Routing" = "Маршрутизація IPv4"
|
||||
"ipv4RoutingDesc" = "Ці параметри спрямовуватимуть трафік на основі певного призначення через IPv4."
|
||||
"warpRouting" = "WARP Маршрутизація"
|
||||
"warpRoutingDesc" = "Ці параметри маршрутизуватимуть трафік на основі певного пункту призначення через WARP."
|
||||
"Template" = "Шаблон розширеної конфігурації Xray"
|
||||
"TemplateDesc" = "Остаточний конфігураційний файл Xray буде створено на основі цього шаблону."
|
||||
"FreedomStrategy" = "Стратегія протоколу свободи"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "Установити загальну стратегію маршрутизації трафіку для вирішення всіх запитів."
|
||||
"Torrent" = "Блокувати протокол BitTorrent"
|
||||
"TorrentDesc" = "Блокує протокол BitTorrent."
|
||||
"PrivateIp" = "Блокувати підключення до приватних IP-адрес"
|
||||
"PrivateIpDesc" = "Блокує встановлення підключень до приватних діапазонів IP."
|
||||
"Ads" = "Блокувати рекламу"
|
||||
"AdsDesc" = "Блокує рекламні веб-сайти."
|
||||
"Family" = "Захист сім'ї"
|
||||
"FamilyDesc" = "Блокує вміст для дорослих і веб-сайти з шкідливими програмами."
|
||||
"Security" = "Щит безпеки"
|
||||
"SecurityDesc" = "Блокує веб-сайти шкідливого програмного забезпечення, фішингу та майнерів."
|
||||
"Speedtest" = "Заблокувати Speedtest"
|
||||
"SpeedtestDesc" = "Блокує підключення до веб-сайтів для тестування швидкості."
|
||||
"IRIp" = "Блокувати підключення до IP-адрес Ірану"
|
||||
"IRIpDesc" = "Блокує встановлення з'єднань з діапазонами IP Ірану."
|
||||
"IRDomain" = "Блокувати підключення до доменів Ірану"
|
||||
"IRDomainDesc" = "Блокує встановлення з'єднань з доменами Ірану."
|
||||
"ChinaIp" = "Блокувати підключення до IP-адрес Китаю"
|
||||
"ChinaIpDesc" = "Блокує встановлення з'єднань із діапазонами IP-адрес Китаю."
|
||||
"ChinaDomain" = "Блокувати підключення до китайських доменів"
|
||||
"ChinaDomainDesc" = "Блокує встановлення підключень до доменів Китаю."
|
||||
"RussiaIp" = "Блокувати підключення до російських IP-адрес"
|
||||
"RussiaIpDesc" = "Блокує встановлення з'єднань з діапазонами IP-адрес Росії."
|
||||
"RussiaDomain" = "Блокувати підключення до російських доменів"
|
||||
"RussiaDomainDesc" = "Блокує встановлення з'єднань з російськими доменами."
|
||||
"VNIp" = "Блокувати підключення до IP-адрес В'єтнаму"
|
||||
"VNIpDesc" = "Блокує встановлення з'єднань із діапазонами IP-адрес В'єтнаму."
|
||||
"VNDomain" = "Блокувати підключення до доменів В'єтнаму"
|
||||
"VNDomainDesc" = "Блокує встановлення з'єднань із доменами В'єтнаму."
|
||||
"DirectIRIp" = "Пряме підключення до IP-адрес Ірану"
|
||||
"DirectIRIpDesc" = "Безпосередньо встановлює з'єднання з діапазонами IP Ірану."
|
||||
"DirectIRDomain" = "Пряме підключення до доменів Ірану"
|
||||
"DirectIRDomainDesc" = "Безпосередньо встановлює підключення до доменів Ірану."
|
||||
"DirectChinaIp" = "Пряме підключення до китайських IP-адрес"
|
||||
"DirectChinaIpDesc" = "Безпосередньо встановлює підключення до IP-діапазонів Китаю."
|
||||
"DirectChinaDomain" = "Пряме підключення до китайських доменів"
|
||||
"DirectChinaDomainDesc" = "Безпосередньо встановлює підключення до доменів Китаю."
|
||||
"DirectRussiaIp" = "Пряме підключення до IP-адрес Росії"
|
||||
"DirectRussiaIpDesc" = "Безпосередньо встановлює з'єднання з діапазонами IP-адрес Росії."
|
||||
"DirectRussiaDomain" = "Пряме підключення до російських доменів"
|
||||
"DirectRussiaDomainDesc" = "Безпосередньо встановлює підключення до російських доменів."
|
||||
"DirectVNIp" = "Пряме підключення до IP-адрес В'єтнаму"
|
||||
"DirectVNIpDesc" = "Безпосередньо встановлює з'єднання з діапазонами IP-адрес В'єтнаму."
|
||||
"DirectVNDomain" = "Пряме підключення до доменів В'єтнаму"
|
||||
"DirectVNDomainDesc" = "Безпосередньо встановлює з'єднання з доменами В'єтнаму."
|
||||
"GoogleIPv4" = "Google"
|
||||
"GoogleIPv4Desc" = "Направляє трафік до Google через IPv4."
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "Направляє трафік до Netflix через IPv4."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Додати маршрутизацію для Google через WARP."
|
||||
"OpenAIWARP" = "ChatGPT"
|
||||
"OpenAIWARPDesc" = "Направляє трафік до ChatGPT через WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Направляє трафік до Netflix через WARP."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Направляє трафік до Meta (Instagram, Facebook, WhatsApp, Threads,...) через WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Направляє трафік до Apple через WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Направляє трафік до Reddit через WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Направляє трафік до Spotify через WARP."
|
||||
"IRWARP" = "Іранські домени"
|
||||
"IRWARPDesc" = "Направляє трафік до доменів Ірану через WARP"
|
||||
"Inbounds" = "Вхідні"
|
||||
"InboundsDesc" = "Прийняття певних клієнтів."
|
||||
"Outbounds" = "Вихід"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "Шлях до файлу журналу доступу. Спеціальне значення 'none' вимикає журнали доступу"
|
||||
"errorLog" = "Журнал помилок"
|
||||
"errorLogDesc" = "Шлях до файлу журналу помилок. Спеціальне значення 'none' вимикає журнали помилок"
|
||||
"dnsLog" = "Журнал DNS"
|
||||
"dnsLogDesc" = "Чи включити журнали запитів DNS"
|
||||
"maskAddress" = "Маскувати Адресу"
|
||||
"maskAddressDesc" = "Маска IP-адреси, при активації автоматично замінює IP-адресу, яка з'являється у журналі."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "Перший"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Додати сервер"
|
||||
"edit" = "Редагувати сервер"
|
||||
"domains" = "Домени"
|
||||
"expectIPs" = "Очікувані IP"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Додати підроблений DNS"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ Бот в порядку!"
|
||||
"usage" = "❗ Введіть текст для пошуку!"
|
||||
"getID" = "🆔 Ваш ідентифікатор: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Для пошуку електронної пошти клієнта:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nДля пошуку вхідних (зі статистикою клієнта):\r\n<code>/inbound [Примітка]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "Для перезапуску Xray Core:\r\n<code>/restart force</code>\r\n\r\nДля пошуку електронної пошти клієнта:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nДля пошуку вхідних (зі статистикою клієнта):\r\n<code>/inbound [Примітка]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "Для пошуку статистики використовуйте наступну команду:\r\n<code>/usage [Електронна пошта]</code>\r\n\r\nID чату Telegram:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ Операція успішна!"
|
||||
"restartFailed" = "❗ Помилка в операції.\r\n\r\n<code>Помилка: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core не запущений."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 Навантаження ЦП {{ .Percent }}% перевищує порогове значення {{ .Threshold }}%"
|
||||
@@ -640,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }}: Успішно вимкнено."
|
||||
"askToAddUserId" = "Вашу конфігурацію не знайдено!\r\nБудь ласка, попросіть свого адміністратора використовувати ваш ідентифікатор Telegram у вашій конфігурації.\r\n\r\nВаш ідентифікатор користувача: <code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "Виберіть клієнта для Вхідного {{ .Inbound }}"
|
||||
"chooseInbound" = "Виберіть Вхідний"
|
||||
"chooseInbound" = "Виберіть Вхідний"
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "Cổng đích"
|
||||
"targetAddress" = "Địa chỉ mục tiêu"
|
||||
"monitorDesc" = "Mặc định để trống"
|
||||
"meansNoLimit" = " = Không giới hạn (đơn vị: GB)"
|
||||
"meansNoLimit" = "= Không giới hạn (đơn vị: GB)"
|
||||
"totalFlow" = "Tổng lưu lượng"
|
||||
"leaveBlankToNeverExpire" = "Để trống để không bao giờ hết hạn"
|
||||
"noRecommendKeepDefault" = "Không yêu cầu đặc biệt để giữ nguyên cài đặt mặc định"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "Lịch sử đăng nhập IP (trước khi kích hoạt điểm vào sau khi bị vô hiệu hóa bởi giới hạn IP, bạn nên xóa lịch sử)."
|
||||
"IPLimitlogclear" = "Xóa Lịch sử"
|
||||
"setDefaultCert" = "Đặt chứng chỉ từ bảng điều khiển"
|
||||
"xtlsDesc" = "Xray core cần phiên bản 1.7.5"
|
||||
"realityDesc" = "Xray core cần phiên bản 1.8.0 hoặc cao hơn."
|
||||
"telegramDesc" = "Vui lòng cung cấp ID Trò chuyện Telegram. (sử dụng lệnh '/id' trong bot) hoặc (@userinfobot)"
|
||||
"subscriptionDesc" = "Bạn có thể tìm liên kết gói đăng ký của mình trong Chi tiết, cũng như bạn có thể sử dụng cùng tên cho nhiều cấu hình khác nhau"
|
||||
"info" = "Thông tin"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "Bạn phải nhận token từ quản lý bot Telegram @botfather"
|
||||
"telegramProxy" = "Socks5 Proxy"
|
||||
"telegramProxyDesc" = "Nếu bạn cần socks5 proxy để kết nối với Telegram. Điều chỉnh cài đặt của nó theo hướng dẫn."
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
"telegramAPIServerDesc" = "Máy chủ API Telegram để sử dụng. Để trống để sử dụng máy chủ mặc định."
|
||||
"telegramChatId" = "Chat ID Telegram của quản trị viên"
|
||||
"telegramChatIdDesc" = "Nhiều Chat ID phân tách bằng dấu phẩy. Sử dụng @userinfobot hoặc sử dụng lệnh '/id' trong bot để lấy Chat ID của bạn."
|
||||
"telegramNotifyTime" = "Thời gian thông báo của bot Telegram"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "Sự phân mảnh"
|
||||
"fragmentDesc" = "Kích hoạt phân mảnh cho gói TLS hello"
|
||||
"fragmentSett" = "Cài đặt phân mảnh"
|
||||
"noiseDesc" = "Bật Noise."
|
||||
"noiseSett" = "Cài đặt Noise"
|
||||
"noisesDesc" = "Bật Noises."
|
||||
"noisesSett" = "Cài đặt Noises"
|
||||
"mux" = "Mux"
|
||||
"muxDesc" = "Truyền nhiều luồng dữ liệu độc lập trong luồng dữ liệu đã thiết lập."
|
||||
"muxSett" = "Mux Cài đặt"
|
||||
"direct" = "Kết nối trực tiếp"
|
||||
"directDesc" = "Trực tiếp thiết lập kết nối với tên miền hoặc dải IP của một quốc gia cụ thể."
|
||||
"directSett" = "Tùy chọn kết nối trực tiếp"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Cài đặt Xray"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "Nhật ký có thể ảnh hưởng đến hiệu suất máy chủ của bạn. Bạn chỉ nên kích hoạt nó một cách khôn ngoan trong trường hợp bạn cần"
|
||||
"blockConfigs" = "Cấu hình Chặn"
|
||||
"blockConfigsDesc" = "Những tùy chọn này sẽ ngăn người dùng kết nối đến các giao thức và trang web cụ thể."
|
||||
"blockCountryConfigs" = "Cấu hình Chặn Quốc gia"
|
||||
"blockCountryConfigsDesc" = "Những tùy chọn này sẽ ngăn người dùng kết nối đến các tên miền quốc gia cụ thể."
|
||||
"directCountryConfigs" = "Cấu hình Kết nối Trực tiếp Quốc gia"
|
||||
"directCountryConfigsDesc" = "Một kết nối trực tiếp đảm bảo rằng lưu lượng cụ thể không được định tuyến qua một máy chủ khác."
|
||||
"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" = "Cảnh báo: Trước khi sử dụng những tùy chọn này, hãy cài đặt WARP ở chế độ proxy socks5 trên máy chủ của bạn bằng cách làm theo các bước trên GitHub của bảng điều khiển. WARP sẽ định tuyến lưu lượng đến các trang web qua máy chủ Cloudflare."
|
||||
"basicRouting" = "Định tuyến Cơ bản"
|
||||
"blockConnectionsConfigsDesc" = "Các tùy chọn này sẽ chặn lưu lượng truy cập dựa trên quốc gia được yêu cầu cụ thể."
|
||||
"directConnectionsConfigsDesc" = "Kết nối trực tiếp đảm bảo rằng lưu lượng truy cập cụ thể không được định tuyến qua máy chủ khác."
|
||||
"blockips" = "Chặn IP"
|
||||
"blockdomains" = "Chặn Tên Miền"
|
||||
"directips" = "IP Trực Tiếp"
|
||||
"directdomains" = "Tên Miền Trực Tiếp"
|
||||
"ipv4Routing" = "Định tuyến IPv4"
|
||||
"ipv4RoutingDesc" = "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."
|
||||
"warpRouting" = "Định tuyến WARP"
|
||||
"warpRoutingDesc" = "Cảnh báo: Trước khi sử dụng những tùy chọn này, hãy cài đặt WARP ở chế độ proxy socks5 trên máy chủ của bạn bằng cách làm theo các bước trên GitHub của bảng điều khiển. 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 Freedom"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "Đặt chiến lược định tuyến tổng thể cho việc giải quyết DNS."
|
||||
"Torrent" = "Cấu hình sử dụng BitTorrent"
|
||||
"TorrentDesc" = "Thay đổi mẫu cấu hình để tránh việc người dùng sử dụng BitTorrent."
|
||||
"PrivateIp" = "Cấm kết nối đến dải IP Riêng tư"
|
||||
"PrivateIpDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến dải IP riêng tư."
|
||||
"Ads" = "Chặn Quảng cáo"
|
||||
"AdsDesc" = "Thay đổi mẫu cấu hình để chặn quảng cáo."
|
||||
"Family" = "Chặn phần mềm độc hại và nội dung người lớn"
|
||||
"FamilyDesc" = "Trình phân giải DNS của Cloudflare để chặn phần mềm độc hại và nội dung người lớn để bảo vệ gia đình."
|
||||
"Security" = "Chặn các trang web chứa phần mềm độc hại, lừa đảo và khai thác tiền điện tử"
|
||||
"SecurityDesc" = "Thay đổi mẫu cấu hình để bảo vệ Bảo mật."
|
||||
"Speedtest" = "Chặn Trang web Speedtest"
|
||||
"SpeedtestDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến các trang web Speedtest."
|
||||
"IRIp" = "Vô hiệu hóa kết nối đến dải IP của Iran"
|
||||
"IRIpDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến dải IP của Iran."
|
||||
"IRDomain" = "Vô hiệu hóa kết nối đến tên miền của Iran"
|
||||
"IRDomainDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến các tên miền của Iran."
|
||||
"ChinaIp" = "Vô hiệu hóa kết nối đến dải IP của Trung Quốc"
|
||||
"ChinaIpDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến dải IP của Trung Quốc."
|
||||
"ChinaDomain" = "Vô hiệu hóa kết nối đến tên miền của Trung Quốc"
|
||||
"ChinaDomainDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến các tên miền của Trung Quốc."
|
||||
"RussiaIp" = "Vô hiệu hóa kết nối đến dải IP của Nga"
|
||||
"RussiaIpDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến dải IP của Nga."
|
||||
"RussiaDomain" = "Vô hiệu hóa kết nối đến tên miền của Nga"
|
||||
"RussiaDomainDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến các tên miền của Nga."
|
||||
"VNIp" = "Vô hiệu hóa kết nối đến dải IP của Việt Nam"
|
||||
"VNIpDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến dải IP của Việt Nam."
|
||||
"VNDomain" = "Vô hiệu hóa kết nối đến tên miền của Việt Nam"
|
||||
"VNDomainDesc" = "Thay đổi mẫu cấu hình để tránh kết nối đến các tên miền của Việt Nam."
|
||||
"DirectIRIp" = "Kết nối trực tiếp đến dải IP của Iran"
|
||||
"DirectIRIpDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến dải IP của Iran."
|
||||
"DirectIRDomain" = "Kết nối trực tiếp đến tên miền của Iran"
|
||||
"DirectIRDomainDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến các tên miền của Iran."
|
||||
"DirectChinaIp" = "Kết nối trực tiếp đến dải IP của Trung Quốc"
|
||||
"DirectChinaIpDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến dải IP của Trung Quốc."
|
||||
"DirectChinaDomain" = "Kết nối trực tiếp đến tên miền của Trung Quốc"
|
||||
"DirectChinaDomainDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến các tên miền của Trung Quốc."
|
||||
"DirectRussiaIp" = "Kết nối trực tiếp đến dải IP của Nga"
|
||||
"DirectRussiaIpDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến dải IP của Nga."
|
||||
"DirectRussiaDomain" = "Kết nối trực tiếp đến tên miền của Nga"
|
||||
"DirectRussiaDomainDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến các tên miền của Nga."
|
||||
"DirectVNIp" = "Kết nối trực tiếp đến dải IP của Việt Nam"
|
||||
"DirectVNIpDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến dải IP của Việt Nam"
|
||||
"DirectVNDomain" = "Kết nối trực tiếp đến tên miền của Việt Nam"
|
||||
"DirectVNDomainDesc" = "Thay đổi mẫu cấu hình cho kết nối trực tiếp đến các tên miền của Việt Nam."
|
||||
"GoogleIPv4" = "Sử dụng IPv4 cho Google"
|
||||
"GoogleIPv4Desc" = "Thêm định tuyến cho Google để kết nối qua IPv4."
|
||||
"NetflixIPv4" = "Sử dụng IPv4 cho Netflix"
|
||||
"NetflixIPv4Desc" = "Thêm định tuyến cho Netflix để kết nối qua IPv4."
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "Định tuyến lưu lượng truy cập tới Google thông qua WARP."
|
||||
"OpenAIWARP" = "OpenAI (ChatGPT)"
|
||||
"OpenAIWARPDesc" = "Định tuyến lưu lượng truy cập tới OpenAI (ChatGPT) thông qua WARP."
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "Định tuyến lưu lượng truy cập tới Netflix thông qua WARP."
|
||||
"MetaWARP" = "Meta"
|
||||
"MetaWARPDesc" = "Định tuyến lưu lượng truy cập tới Meta (Instagram, Facebook, WhatsApp, Threads,...) thông qua WARP."
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "Định tuyến lưu lượng truy cập tới Apple thông qua WARP."
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "Định tuyến lưu lượng truy cập tới Reddit thông qua WARP."
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "Định tuyến lưu lượng truy cập tới Spotify thông qua WARP."
|
||||
"IRWARP" = "Định tuyến tên miền của Iran qua WARP."
|
||||
"IRWARPDesc" = "Thêm định tuyến cho các tên miền của Iran qua WARP."
|
||||
"Inbounds" = "Đầu vào"
|
||||
"InboundsDesc" = "Thay đổi mẫu cấu hình để chấp nhận các máy khách cụ thể."
|
||||
"Outbounds" = "Đầu ra"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "Đường dẫn tệp cho nhật ký truy cập. Nhật ký truy cập bị vô hiệu hóa có giá trị đặc biệt 'không'"
|
||||
"errorLog" = "Nhật ký lỗi"
|
||||
"errorLogDesc" = "Đường dẫn tệp cho nhật ký lỗi. Nhật ký lỗi bị vô hiệu hóa có giá trị đặc biệt 'không'"
|
||||
"dnsLog" = "Nhật ký DNS"
|
||||
"dnsLogDesc" = "Có bật nhật ký truy vấn DNS không"
|
||||
"maskAddress" = "Ẩn Địa Chỉ"
|
||||
"maskAddressDesc" = "Mặt nạ địa chỉ IP, khi được bật, sẽ tự động thay thế địa chỉ IP xuất hiện trong nhật ký."
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "Đầu tiên"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "Thêm máy chủ"
|
||||
"edit" = "Chỉnh sửa máy chủ"
|
||||
"domains" = "Tên miền"
|
||||
"expectIPs" = "Các IP Dự Kiến"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "Thêm DNS giả"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ Bot hoạt động bình thường!"
|
||||
"usage" = "❗ Vui lòng cung cấp văn bản để tìm kiếm!"
|
||||
"getID" = "🆔 ID của bạn: <code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "Để tìm kiếm email của khách hàng:\r\n<code>/usage [Email]</code>\r\n\r\nĐể tìm kiếm các nhập (với số liệu thống kê của khách hàng):\r\n<code>/inbound [Ghi chú]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "Để khởi động lại Xray Core:\r\n<code>/restart force</code>\r\n\r\nĐể tìm kiếm email của khách hàng:\r\n<code>/usage [Email]</code>\r\n\r\nĐể tìm kiếm các nhập (với số liệu thống kê của khách hàng):\r\n<code>/inbound [Ghi chú]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "Để tìm kiếm thống kê, sử dụng lệnh sau:\r\n<code>/usage [Email]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ Hoạt động thành công!"
|
||||
"restartFailed" = "❗ Lỗi trong quá trình hoạt động.\r\n\r\n<code>Lỗi: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core không chạy."
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 Sử dụng CPU {{ .Percent }}% vượt quá ngưỡng {{ .Threshold }}%"
|
||||
@@ -640,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }} : Đã Tắt Thành Công."
|
||||
"askToAddUserId" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nID người dùng của bạn: <code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "Chọn một Khách hàng cho Inbound {{ .Inbound }}"
|
||||
"chooseInbound" = "Chọn một Inbound"
|
||||
"chooseInbound" = "Chọn một Inbound"
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
"destinationPort" = "目标端口"
|
||||
"targetAddress" = "目标地址"
|
||||
"monitorDesc" = "留空表示监听所有 IP"
|
||||
"meansNoLimit" = " = 无限制(单位:GB)"
|
||||
"meansNoLimit" = "= 无限制(单位:GB)"
|
||||
"totalFlow" = "总流量"
|
||||
"leaveBlankToNeverExpire" = "留空表示永不过期"
|
||||
"noRecommendKeepDefault" = "建议保留默认值"
|
||||
@@ -178,8 +178,6 @@
|
||||
"IPLimitlogDesc" = "IP 历史日志(要启用被禁用的入站流量,请清除日志)"
|
||||
"IPLimitlogclear" = "清除日志"
|
||||
"setDefaultCert" = "从面板设置证书"
|
||||
"xtlsDesc" = "Xray 核心需要 1.7.5"
|
||||
"realityDesc" = "Xray 核心需要 1.8.0 及以上版本"
|
||||
"telegramDesc" = "请提供Telegram聊天ID。(在机器人中使用'/id'命令)或(@userinfobot"
|
||||
"subscriptionDesc" = "要找到你的订阅 URL,请导航到“详细信息”。此外,你可以为多个客户端使用相同的名称。"
|
||||
"info" = "信息"
|
||||
@@ -265,6 +263,8 @@
|
||||
"telegramTokenDesc" = "从 '@BotFather' 获取的 Telegram 机器人令牌"
|
||||
"telegramProxy" = "SOCKS5 Proxy"
|
||||
"telegramProxyDesc" = "启用 SOCKS5 代理连接到 Telegram(根据指南调整设置)"
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
"telegramAPIServerDesc" = "要使用的 Telegram API 服务器。留空以使用默认服务器。"
|
||||
"telegramChatId" = "管理员聊天 ID"
|
||||
"telegramChatIdDesc" = "Telegram 管理员聊天 ID (多个以逗号分隔)(可通过 @userinfobot 获取,或在机器人中使用 '/id' 命令获取)"
|
||||
"telegramNotifyTime" = "通知时间"
|
||||
@@ -309,14 +309,14 @@
|
||||
"fragment" = "分片"
|
||||
"fragmentDesc" = "启用 TLS hello 数据包分片"
|
||||
"fragmentSett" = "设置"
|
||||
"noiseDesc" = "启用 Noise."
|
||||
"noiseSett" = "Noise 设置"
|
||||
"noisesDesc" = "启用 Noises."
|
||||
"noisesSett" = "Noises 设置"
|
||||
"mux" = "多路复用器"
|
||||
"muxDesc" = "在已建立的数据流内传输多个独立的数据流"
|
||||
"muxSett" = "复用器设置"
|
||||
"direct" = "直接连接"
|
||||
"directDesc" = "直接与特定国家的域或IP范围建立连接"
|
||||
"directSett" = "直接连接选项"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray 配置"
|
||||
@@ -330,14 +330,17 @@
|
||||
"logConfigsDesc" = "日志可能会影响服务器的性能,建议仅在需要时启用"
|
||||
"blockConfigs" = "防护屏蔽"
|
||||
"blockConfigsDesc" = "这些选项将阻止用户连接到特定协议和网站"
|
||||
"blockCountryConfigs" = "屏蔽国家/地区"
|
||||
"blockCountryConfigsDesc" = "这些选项将阻止用户连接到特定国家/地区"
|
||||
"directCountryConfigs" = "直连国家/地区"
|
||||
"directCountryConfigsDesc" = "直接连接可确保特定流量不会通过其他服务器路由"
|
||||
"ipv4Configs" = "IPv4 路由"
|
||||
"ipv4ConfigsDesc" = "此选项将仅通过 IPv4 路由到目标域"
|
||||
"warpConfigs" = "WARP 路由"
|
||||
"warpConfigsDesc" = "注意:在使用这些选项之前,请按照面板 GitHub 上的步骤在你的服务器上以 socks5 代理模式安装 WARP。WARP 将通过 Cloudflare 服务器将流量路由到网站。"
|
||||
"basicRouting" = "基本路由"
|
||||
"blockConnectionsConfigsDesc" = "这些选项将根据特定的请求国家阻止流量。"
|
||||
"directConnectionsConfigsDesc" = "直接连接确保特定的流量不会通过其他服务器路由。"
|
||||
"blockips" = "阻止IP"
|
||||
"blockdomains" = "阻止域名"
|
||||
"directips" = "直接IP"
|
||||
"directdomains" = "直接域名"
|
||||
"ipv4Routing" = "IPv4 路由"
|
||||
"ipv4RoutingDesc" = "此选项将仅通过 IPv4 路由到目标域"
|
||||
"warpRouting" = "WARP 路由"
|
||||
"warpRoutingDesc" = "注意:在使用这些选项之前,请按照面板 GitHub 上的步骤在你的服务器上以 socks5 代理模式安装 WARP。WARP 将通过 Cloudflare 服务器将流量路由到网站。"
|
||||
"Template" = "高级 Xray 配置模板"
|
||||
"TemplateDesc" = "最终的 Xray 配置文件将基于此模板生成"
|
||||
"FreedomStrategy" = "Freedom 协议策略"
|
||||
@@ -346,68 +349,8 @@
|
||||
"RoutingStrategyDesc" = "设置 DNS 解析的整体路由策略"
|
||||
"Torrent" = "屏蔽 BitTorrent 协议"
|
||||
"TorrentDesc" = "禁止使用 BitTorrent"
|
||||
"PrivateIp" = "屏蔽私有 IP"
|
||||
"PrivateIpDesc" = "阻止连接到私有 IP"
|
||||
"Ads" = "屏蔽广告"
|
||||
"AdsDesc" = "屏蔽广告网站"
|
||||
"Family" = "家庭保护"
|
||||
"FamilyDesc" = "屏蔽成人内容和恶意网站"
|
||||
"Security" = "安全防护"
|
||||
"SecurityDesc" = "屏蔽恶意软件、网络钓鱼和挖矿网站"
|
||||
"Speedtest" = "屏蔽测速网站"
|
||||
"SpeedtestDesc" = "阻止连接到测速网站"
|
||||
"IRIp" = "屏蔽连接到伊朗 IP"
|
||||
"IRIpDesc" = "阻止建立到伊朗 IP 范围的连接"
|
||||
"IRDomain" = "屏蔽连接到伊朗域名"
|
||||
"IRDomainDesc" = "阻止建立到伊朗域名的连接"
|
||||
"ChinaIp" = "屏蔽连接到中国 IP"
|
||||
"ChinaIpDesc" = "阻止建立到中国 IP 范围的连接"
|
||||
"ChinaDomain" = "屏蔽连接到中国域名"
|
||||
"ChinaDomainDesc" = "阻止建立到中国域名的连接"
|
||||
"RussiaIp" = "屏蔽连接到俄罗斯 IP"
|
||||
"RussiaIpDesc" = "阻止建立到俄罗斯 IP 范围的连接"
|
||||
"RussiaDomain" = "屏蔽连接到俄罗斯域名"
|
||||
"RussiaDomainDesc" = "阻止建立到俄罗斯域名的连接"
|
||||
"VNIp" = "屏蔽连接到越南 IP"
|
||||
"VNIpDesc" = "阻止建立到越南 IP 范围的连接"
|
||||
"VNDomain" = "屏蔽连接到越南域名"
|
||||
"VNDomainDesc" = "阻止建立到越南域名的连接"
|
||||
"DirectIRIp" = "直连伊朗 IP"
|
||||
"DirectIRIpDesc" = "直接建立到伊朗 IP 范围的连接"
|
||||
"DirectIRDomain" = "直连伊朗域名"
|
||||
"DirectIRDomainDesc" = "直接建立到伊朗域名的连接"
|
||||
"DirectChinaIp" = "直连中国 IP"
|
||||
"DirectChinaIpDesc" = "直接建立到中国 IP 范围的连接"
|
||||
"DirectChinaDomain" = "直连中国域名"
|
||||
"DirectChinaDomainDesc" = "直接建立到中国域名的连接"
|
||||
"DirectRussiaIp" = "直连俄罗斯 IP"
|
||||
"DirectRussiaIpDesc" = "直接建立到俄罗斯 IP 范围的连接"
|
||||
"DirectRussiaDomain" = "直连俄罗斯域名"
|
||||
"DirectRussiaDomainDesc" = "直接建立到俄罗斯域名的连接"
|
||||
"DirectVNIp" = "直连越南 IP"
|
||||
"DirectVNIpDesc" = "直接建立到越南 IP 范围的连接"
|
||||
"DirectVNDomain" = "直连越南域名"
|
||||
"DirectVNDomainDesc" = "直接建立到越南域名的连接"
|
||||
"GoogleIPv4" = "Google"
|
||||
"GoogleIPv4Desc" = "通过 IPv4 将流量路由到谷歌"
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "通过 IPv4 将流量路由到 Netflix"
|
||||
"GoogleWARP" = "Google"
|
||||
"GoogleWARPDesc" = "通过 WARP 将流量路由到 Google"
|
||||
"OpenAIWARP" = "OpenAI (ChatGPT)"
|
||||
"OpenAIWARPDesc" = "通过 WARP 将流量路由到 OpenAI (ChatGPT)"
|
||||
"NetflixWARP" = "Netflix"
|
||||
"NetflixWARPDesc" = "通过 WARP 将流量路由到 Netflix"
|
||||
"MetaWARP"="Meta"
|
||||
"MetaWARPDesc" = "通过 WARP 将流量路由到 Meta(Instagram、Facebook、WhatsApp、Threads...)"
|
||||
"AppleWARP" = "Apple"
|
||||
"AppleWARPDesc" = "通过 WARP 将流量路由到 Apple"
|
||||
"RedditWARP" = "Reddit"
|
||||
"RedditWARPDesc" = "通过 WARP 将流量路由到 Reddit"
|
||||
"SpotifyWARP" = "Spotify"
|
||||
"SpotifyWARPDesc" = "通过 WARP 将流量路由到 Spotify"
|
||||
"IRWARP" = "伊朗域名"
|
||||
"IRWARPDesc" = "通过 WARP 将流量路由到伊朗域名"
|
||||
"Inbounds" = "入站规则"
|
||||
"InboundsDesc" = "接受来自特定客户端的流量"
|
||||
"Outbounds" = "出站规则"
|
||||
@@ -422,6 +365,10 @@
|
||||
"accessLogDesc" = "访问日志的文件路径。特殊值 'none' 禁用访问日志"
|
||||
"errorLog" = "错误日志"
|
||||
"errorLogDesc" = "错误日志的文件路径。特殊值 'none' 禁用错误日志"
|
||||
"dnsLog" = "DNS 日志"
|
||||
"dnsLogDesc" = "是否启用 DNS 查询日志"
|
||||
"maskAddress" = "隐藏地址"
|
||||
"maskAddressDesc" = "IP 地址掩码,启用时会自动替换日志中出现的 IP 地址。"
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "置顶"
|
||||
@@ -484,6 +431,7 @@
|
||||
"add" = "添加服务器"
|
||||
"edit" = "编辑服务器"
|
||||
"domains" = "域"
|
||||
"expectIPs" = "预期 IP"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "添加假 DNS"
|
||||
@@ -497,7 +445,7 @@
|
||||
"loginSecurity" = "登录安全"
|
||||
"loginSecurityDesc" = "添加额外的身份验证以提高安全性"
|
||||
"secretToken" = "安全令牌"
|
||||
"secretTokenDesc" = "请将此令牌存储在安全的地方。此令牌用于登录,丢失无法恢复。"
|
||||
"secretTokenDesc" = "请将此令牌存储在安全的地方。此令牌用于登录,丢失无法恢复。"
|
||||
|
||||
[pages.settings.toasts]
|
||||
"modifySettings" = "修改设置"
|
||||
@@ -535,8 +483,12 @@
|
||||
"status" = "✅ 机器人正常运行!"
|
||||
"usage" = "❗ 请输入要搜索的文本!"
|
||||
"getID" = "🆔 您的 ID 为:<code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站(带有客户统计数据):\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "要重新启动 Xray Core:\r\n<code>/restart force</code>\r\n\r\n要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站(带有客户统计数据):\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "要搜索统计数据,请使用以下命令:\r\n<code>/usage [电子邮件]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ 操作成功!"
|
||||
"restartFailed" = "❗ 操作错误。\r\n\r\n<code>错误: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core 未运行。"
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%"
|
||||
@@ -640,4 +592,4 @@
|
||||
"disableSuccess" = "✅ {{ .Email }}:已成功禁用。"
|
||||
"askToAddUserId" = "未找到您的配置!\r\n请向管理员询问,在您的配置中使用您的 Telegram 用户 ChatID。\r\n\r\n您的用户 ChatID:<code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "为入站 {{ .Inbound }} 选择一个客户"
|
||||
"chooseInbound" = "选择一个入站"
|
||||
"chooseInbound" = "选择一个入站"
|
||||
|
||||
595
web/translation/translate.zh_TW.toml
Normal file
595
web/translation/translate.zh_TW.toml
Normal file
@@ -0,0 +1,595 @@
|
||||
"username" = "使用者名稱"
|
||||
"password" = "密碼"
|
||||
"login" = "登入"
|
||||
"confirm" = "確定"
|
||||
"cancel" = "取消"
|
||||
"close" = "關閉"
|
||||
"copy" = "複製"
|
||||
"copied" = "已複製"
|
||||
"download" = "下載"
|
||||
"remark" = "備註"
|
||||
"enable" = "啟用"
|
||||
"protocol" = "協議"
|
||||
"search" = "搜尋"
|
||||
"filter" = "篩選"
|
||||
"loading" = "載入中..."
|
||||
"second" = "秒"
|
||||
"minute" = "分鐘"
|
||||
"hour" = "小時"
|
||||
"day" = "天"
|
||||
"check" = "檢視"
|
||||
"indefinite" = "無限期"
|
||||
"unlimited" = "無限制"
|
||||
"none" = "無"
|
||||
"qrCode" = "二維碼"
|
||||
"info" = "更多資訊"
|
||||
"edit" = "編輯"
|
||||
"delete" = "刪除"
|
||||
"reset" = "重置"
|
||||
"copySuccess" = "複製成功"
|
||||
"sure" = "確定"
|
||||
"encryption" = "加密"
|
||||
"transmission" = "傳輸"
|
||||
"host" = "主機"
|
||||
"path" = "路徑"
|
||||
"camouflage" = "偽裝"
|
||||
"status" = "狀態"
|
||||
"enabled" = "開啟"
|
||||
"disabled" = "關閉"
|
||||
"depleted" = "耗盡"
|
||||
"depletingSoon" = "即將耗盡"
|
||||
"offline" = "離線"
|
||||
"online" = "線上"
|
||||
"domainName" = "域名"
|
||||
"monitor" = "監聽"
|
||||
"certificate" = "憑證"
|
||||
"fail" = "失敗"
|
||||
"success" = "成功"
|
||||
"getVersion" = "獲取版本"
|
||||
"install" = "安裝"
|
||||
"clients" = "客戶端"
|
||||
"usage" = "使用情況"
|
||||
"secretToken" = "安全金鑰"
|
||||
"remained" = "剩餘"
|
||||
"security" = "安全"
|
||||
"secAlertTitle" = "安全警報"
|
||||
"secAlertSsl" = "此連線不安全。在啟用 TLS 進行資料保護之前,請勿輸入敏感資訊。"
|
||||
"secAlertConf" = "某些設定易受攻擊。建議加強安全協議以防止潛在漏洞。"
|
||||
"secAlertSSL" = "面板缺少安全連線。請安裝 TLS 證書以保護資料安全。"
|
||||
"secAlertPanelPort" = "面板預設埠存在安全風險。請配置隨機埠或特定埠。"
|
||||
"secAlertPanelURI" = "面板預設 URI 路徑不安全。請配置複雜的 URI 路徑。"
|
||||
"secAlertSubURI" = "訂閱預設 URI 路徑不安全。請配置複雜的 URI 路徑。"
|
||||
"secAlertSubJsonURI" = "訂閱 JSON 預設 URI 路徑不安全。請配置複雜的 URI 路徑。"
|
||||
|
||||
[menu]
|
||||
"dashboard" = "系統狀態"
|
||||
"inbounds" = "入站列表"
|
||||
"settings" = "面板設定"
|
||||
"xray" = "Xray 設定"
|
||||
"logout" = "退出登入"
|
||||
"link" = "管理"
|
||||
|
||||
[pages.login]
|
||||
"hello" = "你好"
|
||||
"title" = "歡迎"
|
||||
"loginAgain" = "登入時效已過,請重新登入"
|
||||
|
||||
[pages.login.toasts]
|
||||
"invalidFormData" = "資料格式錯誤"
|
||||
"emptyUsername" = "請輸入使用者名稱"
|
||||
"emptyPassword" = "請輸入密碼"
|
||||
"wrongUsernameOrPassword" = "使用者名稱或密碼錯誤"
|
||||
"successLogin" = "登入"
|
||||
|
||||
[pages.index]
|
||||
"title" = "系統狀態"
|
||||
"memory" = "記憶體"
|
||||
"hard" = "磁碟"
|
||||
"xrayStatus" = "Xray"
|
||||
"stopXray" = "停止"
|
||||
"restartXray" = "重啟"
|
||||
"xraySwitch" = "版本"
|
||||
"xraySwitchClick" = "選擇你要切換到的版本"
|
||||
"xraySwitchClickDesk" = "請謹慎選擇,因為較舊版本可能與當前配置不相容"
|
||||
"operationHours" = "系統正常執行時間"
|
||||
"systemLoad" = "系統負載"
|
||||
"systemLoadDesc" = "過去 1、5 和 15 分鐘的系統平均負載"
|
||||
"connectionTcpCountDesc" = "系統中所有 TCP 連線數"
|
||||
"connectionUdpCountDesc" = "系統中所有 UDP 連線數"
|
||||
"connectionCount" = "連線數"
|
||||
"upSpeed" = "總上傳速度"
|
||||
"downSpeed" = "總下載速度"
|
||||
"totalSent" = "系統啟動以來傳送的總資料量"
|
||||
"totalReceive" = "系統啟動以來接收的總資料量"
|
||||
"xraySwitchVersionDialog" = "切換 Xray 版本"
|
||||
"xraySwitchVersionDialogDesc" = "是否切換 Xray 版本至"
|
||||
"dontRefresh" = "安裝中,請勿重新整理此頁面"
|
||||
"logs" = "日誌"
|
||||
"config" = "配置"
|
||||
"backup" = "備份和恢復"
|
||||
"backupTitle" = "備份和恢復資料庫"
|
||||
"backupDescription" = "恢復資料庫之前建議進行備份"
|
||||
"exportDatabase" = "備份"
|
||||
"importDatabase" = "恢復"
|
||||
|
||||
[pages.inbounds]
|
||||
"title" = "入站列表"
|
||||
"totalDownUp" = "總上傳 / 下載"
|
||||
"totalUsage" = "總用量"
|
||||
"inboundCount" = "入站數量"
|
||||
"operate" = "選單"
|
||||
"enable" = "啟用"
|
||||
"remark" = "備註"
|
||||
"protocol" = "協議"
|
||||
"port" = "埠"
|
||||
"traffic" = "流量"
|
||||
"details" = "詳細資訊"
|
||||
"transportConfig" = "傳輸配置"
|
||||
"expireDate" = "到期時間"
|
||||
"resetTraffic" = "重置流量"
|
||||
"addInbound" = "新增入站"
|
||||
"generalActions" = "通用操作"
|
||||
"create" = "新增"
|
||||
"update" = "修改"
|
||||
"modifyInbound" = "修改入站"
|
||||
"deleteInbound" = "刪除入站"
|
||||
"deleteInboundContent" = "確定要刪除入站嗎?"
|
||||
"deleteClient" = "刪除客戶端"
|
||||
"deleteClientContent" = "確定要刪除客戶端嗎?"
|
||||
"resetTrafficContent" = "確定要重置流量嗎?"
|
||||
"copyLink" = "複製連結"
|
||||
"address" = "地址"
|
||||
"network" = "網路"
|
||||
"destinationPort" = "目標埠"
|
||||
"targetAddress" = "目標地址"
|
||||
"monitorDesc" = "留空表示監聽所有 IP"
|
||||
"meansNoLimit" = "= 無限制(單位:GB)"
|
||||
"totalFlow" = "總流量"
|
||||
"leaveBlankToNeverExpire" = "留空表示永不過期"
|
||||
"noRecommendKeepDefault" = "建議保留預設值"
|
||||
"certificatePath" = "檔案路徑"
|
||||
"certificateContent" = "檔案內容"
|
||||
"publicKey" = "公鑰"
|
||||
"privatekey" = "私鑰"
|
||||
"clickOnQRcode" = "點選二維碼複製"
|
||||
"client" = "客戶"
|
||||
"export" = "匯出連結"
|
||||
"clone" = "複製"
|
||||
"cloneInbound" = "複製"
|
||||
"cloneInboundContent" = "此入站規則除埠(Port)、監聽 IP(Listening IP)和客戶端(Clients)以外的所有配置都將應用於克隆"
|
||||
"cloneInboundOk" = "建立克隆"
|
||||
"resetAllTraffic" = "重置所有入站流量"
|
||||
"resetAllTrafficTitle" = "重置所有入站流量"
|
||||
"resetAllTrafficContent" = "確定要重置所有入站流量嗎?"
|
||||
"resetInboundClientTraffics" = "重置客戶端流量"
|
||||
"resetInboundClientTrafficTitle" = "重置所有客戶端流量"
|
||||
"resetInboundClientTrafficContent" = "確定要重置此入站客戶端的所有流量嗎?"
|
||||
"resetAllClientTraffics" = "重置所有客戶端流量"
|
||||
"resetAllClientTrafficTitle" = "重置所有客戶端流量"
|
||||
"resetAllClientTrafficContent" = "確定要重置所有客戶端的所有流量嗎?"
|
||||
"delDepletedClients" = "刪除流量耗盡的客戶端"
|
||||
"delDepletedClientsTitle" = "刪除流量耗盡的客戶端"
|
||||
"delDepletedClientsContent" = "確定要刪除所有流量耗盡的客戶端嗎?"
|
||||
"email" = "電子郵件"
|
||||
"emailDesc" = "電子郵件必須完全唯一"
|
||||
"IPLimit" = "IP 限制"
|
||||
"IPLimitDesc" = "如果數量超過設定值,則禁用入站流量。(0 = 禁用)"
|
||||
"IPLimitlog" = "IP 日誌"
|
||||
"IPLimitlogDesc" = "IP 歷史日誌(要啟用被禁用的入站流量,請清除日誌)"
|
||||
"IPLimitlogclear" = "清除日誌"
|
||||
"setDefaultCert" = "從面板設定證書"
|
||||
"telegramDesc" = "請提供Telegram聊天ID。(在機器人中使用'/id'命令)或(@userinfobot"
|
||||
"subscriptionDesc" = "要找到你的訂閱 URL,請導航到“詳細資訊”。此外,你可以為多個客戶端使用相同的名稱。"
|
||||
"info" = "資訊"
|
||||
"same" = "相同"
|
||||
"inboundData" = "入站資料"
|
||||
"exportInbound" = "匯出入站規則"
|
||||
"import"="匯入"
|
||||
"importInbound" = "匯入入站規則"
|
||||
|
||||
[pages.client]
|
||||
"add" = "新增客戶端"
|
||||
"edit" = "編輯客戶端"
|
||||
"submitAdd" = "新增客戶端"
|
||||
"submitEdit" = "儲存修改"
|
||||
"clientCount" = "客戶端數量"
|
||||
"bulk" = "批量建立"
|
||||
"method" = "方法"
|
||||
"first" = "置頂"
|
||||
"last" = "置底"
|
||||
"prefix" = "字首"
|
||||
"postfix" = "字尾"
|
||||
"delayedStart" = "首次使用後開始"
|
||||
"expireDays" = "期間"
|
||||
"days" = "天"
|
||||
"renew" = "自動續訂"
|
||||
"renewDesc" = "到期後自動續訂。(0 = 禁用)(單位: 天)"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "獲取"
|
||||
|
||||
[pages.inbounds.stream.general]
|
||||
"request" = "請求"
|
||||
"response" = "響應"
|
||||
"name" = "名稱"
|
||||
"value" = "值"
|
||||
|
||||
[pages.inbounds.stream.tcp]
|
||||
"version" = "版本"
|
||||
"method" = "方法"
|
||||
"path" = "路徑"
|
||||
"status" = "狀態"
|
||||
"statusDescription" = "狀態說明"
|
||||
"requestHeader" = "請求頭"
|
||||
"responseHeader" = "響應頭"
|
||||
|
||||
[pages.settings]
|
||||
"title" = "面板設定"
|
||||
"save" = "儲存"
|
||||
"infoDesc" = "此處的所有更改都需要儲存並重啟面板才能生效"
|
||||
"restartPanel" = "重啟面板"
|
||||
"restartPanelDesc" = "確定要重啟面板嗎?若重啟後無法訪問面板,請前往伺服器檢視面板日誌資訊"
|
||||
"actions" = "操作"
|
||||
"resetDefaultConfig" = "重置為預設配置"
|
||||
"panelSettings" = "常規"
|
||||
"securitySettings" = "安全設定"
|
||||
"TGBotSettings" = "Telegram 機器人配置"
|
||||
"panelListeningIP" = "面板監聽 IP"
|
||||
"panelListeningIPDesc" = "預設留空監聽所有 IP"
|
||||
"panelListeningDomain" = "面板監聽域名"
|
||||
"panelListeningDomainDesc" = "預設情況下留空以監視所有域名和 IP 地址"
|
||||
"panelPort" = "面板監聽埠"
|
||||
"panelPortDesc" = "重啟面板生效"
|
||||
"publicKeyPath" = "面板證書公鑰檔案路徑"
|
||||
"publicKeyPathDesc" = "填寫一個 '/' 開頭的絕對路徑"
|
||||
"privateKeyPath" = "面板證書金鑰檔案路徑"
|
||||
"privateKeyPathDesc" = "填寫一個 '/' 開頭的絕對路徑"
|
||||
"panelUrlPath" = "面板 url 根路徑"
|
||||
"panelUrlPathDesc" = "必須以 '/' 開頭,以 '/' 結尾"
|
||||
"pageSize" = "分頁大小"
|
||||
"pageSizeDesc" = "定義入站表的頁面大小。設定 0 表示禁用"
|
||||
"remarkModel" = "備註模型和分隔符"
|
||||
"datepicker" = "日期選擇器"
|
||||
"datepickerPlaceholder" = "選擇日期"
|
||||
"datepickerDescription" = "選擇器日曆類型指定到期日期"
|
||||
"sampleRemark" = "備註示例"
|
||||
"oldUsername" = "原使用者名稱"
|
||||
"currentPassword" = "原密碼"
|
||||
"newUsername" = "新使用者名稱"
|
||||
"newPassword" = "新密碼"
|
||||
"telegramBotEnable" = "啟用 Telegram 機器人"
|
||||
"telegramBotEnableDesc" = "啟用 Telegram 機器人功能"
|
||||
"telegramToken" = "Telegram 機器人令牌(token)"
|
||||
"telegramTokenDesc" = "從 '@BotFather' 獲取的 Telegram 機器人令牌"
|
||||
"telegramProxy" = "SOCKS5 Proxy"
|
||||
"telegramProxyDesc" = "啟用 SOCKS5 代理連線到 Telegram(根據指南調整設定)"
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
"telegramAPIServerDesc" = "要使用的 Telegram API 伺服器。留空以使用預設伺服器。"
|
||||
"telegramChatId" = "管理員聊天 ID"
|
||||
"telegramChatIdDesc" = "Telegram 管理員聊天 ID (多個以逗號分隔)(可通過 @userinfobot 獲取,或在機器人中使用 '/id' 命令獲取)"
|
||||
"telegramNotifyTime" = "通知時間"
|
||||
"telegramNotifyTimeDesc" = "設定週期性的 Telegram 機器人通知時間(使用 crontab 時間格式)"
|
||||
"tgNotifyBackup" = "資料庫備份"
|
||||
"tgNotifyBackupDesc" = "傳送帶有報告的資料庫備份檔案"
|
||||
"tgNotifyLogin" = "登入通知"
|
||||
"tgNotifyLoginDesc" = "當有人試圖登入你的面板時顯示使用者名稱、IP 地址和時間"
|
||||
"sessionMaxAge" = "會話時長"
|
||||
"sessionMaxAgeDesc" = "保持登入狀態的時長(單位:分鐘)"
|
||||
"expireTimeDiff" = "到期通知閾值"
|
||||
"expireTimeDiffDesc" = "達到此閾值時,將收到有關到期時間的通知(單位:天)"
|
||||
"trafficDiff" = "流量耗盡閾值"
|
||||
"trafficDiffDesc" = "達到此閾值時,將收到有關流量耗盡的通知(單位:GB)"
|
||||
"tgNotifyCpu" = "CPU 負載通知閾值"
|
||||
"tgNotifyCpuDesc" = "CPU 負載超過此閾值時,將收到通知(單位:%)"
|
||||
"timeZone" = "時區"
|
||||
"timeZoneDesc" = "定時任務將按照該時區的時間執行"
|
||||
"subSettings" = "訂閱設定"
|
||||
"subEnable" = "啟用訂閱服務"
|
||||
"subEnableDesc" = "啟用訂閱服務功能"
|
||||
"subListen" = "監聽 IP"
|
||||
"subListenDesc" = "訂閱服務監聽的 IP 地址(留空表示監聽所有 IP)"
|
||||
"subPort" = "監聽埠"
|
||||
"subPortDesc" = "訂閱服務監聽的埠號(必須是未使用的埠)"
|
||||
"subCertPath" = "公鑰路徑"
|
||||
"subCertPathDesc" = "訂閱服務使用的公鑰檔案路徑(以 '/' 開頭)"
|
||||
"subKeyPath" = "私鑰路徑"
|
||||
"subKeyPathDesc" = "訂閱服務使用的私鑰檔案路徑(以 '/' 開頭)"
|
||||
"subPath" = "URI 路徑"
|
||||
"subPathDesc" = "訂閱服務使用的 URI 路徑(以 '/' 開頭,以 '/' 結尾)"
|
||||
"subDomain" = "監聽域名"
|
||||
"subDomainDesc" = "訂閱服務監聽的域名(留空表示監聽所有域名和 IP)"
|
||||
"subUpdates" = "更新間隔"
|
||||
"subUpdatesDesc" = "客戶端應用中訂閱 URL 的更新間隔(單位:小時)"
|
||||
"subEncrypt" = "編碼"
|
||||
"subEncryptDesc" = "訂閱服務返回的內容將採用 Base64 編碼"
|
||||
"subShowInfo" = "顯示使用資訊"
|
||||
"subShowInfoDesc" = "客戶端應用中將顯示剩餘流量和日期資訊"
|
||||
"subURI" = "反向代理 URI"
|
||||
"subURIDesc" = "用於代理後面的訂閱 URL 的 URI 路徑"
|
||||
"fragment" = "分片"
|
||||
"fragmentDesc" = "啟用 TLS hello 資料包分片"
|
||||
"fragmentSett" = "設定"
|
||||
"noisesDesc" = "啟用 Noises."
|
||||
"noisesSett" = "Noises 設定"
|
||||
"mux" = "多路複用器"
|
||||
"muxDesc" = "在已建立的資料流內傳輸多個獨立的資料流"
|
||||
"muxSett" = "複用器設定"
|
||||
"direct" = "直接連線"
|
||||
"directDesc" = "直接與特定國家的域或IP範圍建立連線"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray 配置"
|
||||
"save" = "儲存"
|
||||
"restart" = "重新啟動 Xray"
|
||||
"basicTemplate" = "基礎配置"
|
||||
"advancedTemplate" = "高階配置"
|
||||
"generalConfigs" = "常規配置"
|
||||
"generalConfigsDesc" = "這些選項將決定常規配置"
|
||||
"logConfigs" = "日誌"
|
||||
"logConfigsDesc" = "日誌可能會影響伺服器的效能,建議僅在需要時啟用"
|
||||
"blockConfigs" = "防護遮蔽"
|
||||
"blockConfigsDesc" = "這些選項將阻止使用者連線到特定協議和網站"
|
||||
"basicRouting" = "基本路由"
|
||||
"blockConnectionsConfigsDesc" = "這些選項將根據特定的請求國家阻止流量。"
|
||||
"directConnectionsConfigsDesc" = "直接連線確保特定的流量不會通過其他伺服器路由。"
|
||||
"blockips" = "阻止IP"
|
||||
"blockdomains" = "阻止域名"
|
||||
"directips" = "直接IP"
|
||||
"directdomains" = "直接域名"
|
||||
"ipv4Routing" = "IPv4 路由"
|
||||
"ipv4RoutingDesc" = "此選項將僅通過 IPv4 路由到目標域"
|
||||
"warpRouting" = "WARP 路由"
|
||||
"warpRoutingDesc" = "注意:在使用這些選項之前,請按照面板 GitHub 上的步驟在你的伺服器上以 socks5 代理模式安裝 WARP。WARP 將通過 Cloudflare 伺服器將流量路由到網站。"
|
||||
"Template" = "高階 Xray 配置模板"
|
||||
"TemplateDesc" = "最終的 Xray 配置檔案將基於此模板生成"
|
||||
"FreedomStrategy" = "Freedom 協議策略"
|
||||
"FreedomStrategyDesc" = "設定 Freedom 協議中網路的輸出策略"
|
||||
"RoutingStrategy" = "配置路由域策略"
|
||||
"RoutingStrategyDesc" = "設定 DNS 解析的整體路由策略"
|
||||
"Torrent" = "遮蔽 BitTorrent 協議"
|
||||
"TorrentDesc" = "禁止使用 BitTorrent"
|
||||
"Family" = "家庭保護"
|
||||
"FamilyDesc" = "遮蔽成人內容和惡意網站"
|
||||
"Inbounds" = "入站規則"
|
||||
"InboundsDesc" = "接受來自特定客戶端的流量"
|
||||
"Outbounds" = "出站規則"
|
||||
"Balancers" = "負載均衡"
|
||||
"OutboundsDesc" = "設定出站流量傳出方式"
|
||||
"Routings" = "路由規則"
|
||||
"RoutingsDesc" = "每條規則的優先順序都很重要"
|
||||
"completeTemplate" = "全部"
|
||||
"logLevel" = "日誌級別"
|
||||
"logLevelDesc" = "錯誤日誌的日誌級別,用於指示需要記錄的資訊"
|
||||
"accessLog" = "訪問日誌"
|
||||
"accessLogDesc" = "訪問日誌的檔案路徑。特殊值 'none' 禁用訪問日誌"
|
||||
"errorLog" = "錯誤日誌"
|
||||
"errorLogDesc" = "錯誤日誌的檔案路徑。特殊值 'none' 禁用錯誤日誌"
|
||||
"dnsLog" = "DNS 日誌"
|
||||
"dnsLogDesc" = "是否啟用 DNS 查詢日誌"
|
||||
"maskAddress" = "隱藏地址"
|
||||
"maskAddressDesc" = "IP 地址掩碼,啟用時會自動替換日誌中出現的 IP 地址。"
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "置頂"
|
||||
"last" = "置底"
|
||||
"up" = "向上"
|
||||
"down" = "向下"
|
||||
"source" = "來源"
|
||||
"dest" = "目的地址"
|
||||
"inbound" = "入站"
|
||||
"outbound" = "出站"
|
||||
"balancer" = "負載均衡"
|
||||
"info" = "資訊"
|
||||
"add" = "新增規則"
|
||||
"edit" = "編輯規則"
|
||||
"useComma" = "逗號分隔的項目"
|
||||
|
||||
[pages.xray.outbound]
|
||||
"addOutbound" = "新增出站"
|
||||
"addReverse" = "新增反向"
|
||||
"editOutbound" = "編輯出站"
|
||||
"editReverse" = "編輯反向"
|
||||
"tag" = "標籤"
|
||||
"tagDesc" = "唯一標籤"
|
||||
"address" = "地址"
|
||||
"reverse" = "反向"
|
||||
"domain" = "域名"
|
||||
"type" = "類型"
|
||||
"bridge" = "Bridge"
|
||||
"portal" = "Portal"
|
||||
"intercon" = "互連"
|
||||
"settings" = "設定"
|
||||
"accountInfo" = "帳戶資訊"
|
||||
"outboundStatus" = "出站狀態"
|
||||
"sendThrough" = "傳送通過"
|
||||
|
||||
[pages.xray.balancer]
|
||||
"addBalancer" = "新增負載均衡"
|
||||
"editBalancer" = "編輯負載均衡"
|
||||
"balancerStrategy" = "策略"
|
||||
"balancerSelectors" = "選擇器"
|
||||
"tag" = "標籤"
|
||||
"tagDesc" = "唯一標籤"
|
||||
"balancerDesc" = "無法同時使用 balancerTag 和 outboundTag。如果同時使用,則只有 outboundTag 會生效。"
|
||||
|
||||
[pages.xray.wireguard]
|
||||
"secretKey" = "金鑰"
|
||||
"publicKey" = "公鑰"
|
||||
"allowedIPs" = "允許的 IP"
|
||||
"endpoint" = "端點"
|
||||
"psk" = "共享金鑰"
|
||||
"domainStrategy" = "域策略"
|
||||
|
||||
[pages.xray.dns]
|
||||
"enable" = "啟用 DNS"
|
||||
"enableDesc" = "啟用內建 DNS 伺服器"
|
||||
"tag" = "DNS 入站標籤"
|
||||
"tagDesc" = "此標籤將在路由規則中可用作入站標籤"
|
||||
"strategy" = "查詢策略"
|
||||
"strategyDesc" = "解析域名的總體策略"
|
||||
"add" = "新增伺服器"
|
||||
"edit" = "編輯伺服器"
|
||||
"domains" = "域"
|
||||
"expectIPs" = "預期 IP"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "新增假 DNS"
|
||||
"edit" = "編輯假 DNS"
|
||||
"ipPool" = "IP 池子網"
|
||||
"poolSize" = "池大小"
|
||||
|
||||
[pages.settings.security]
|
||||
"admin" = "管理員"
|
||||
"secret" = "安全令牌"
|
||||
"loginSecurity" = "登入安全"
|
||||
"loginSecurityDesc" = "新增額外的身份驗證以提高安全性"
|
||||
"secretToken" = "安全令牌"
|
||||
"secretTokenDesc" = "請將此令牌儲存在安全的地方。此令牌用於登入,丟失無法恢復。"
|
||||
|
||||
[pages.settings.toasts]
|
||||
"modifySettings" = "修改設定"
|
||||
"getSettings" = "獲取設定"
|
||||
"modifyUser" = "修改管理員"
|
||||
"originalUserPassIncorrect" = "原使用者名稱或原密碼錯誤"
|
||||
"userPassMustBeNotEmpty" = "新使用者名稱和新密碼不能為空"
|
||||
|
||||
[tgbot]
|
||||
"keyboardClosed" = "❌ 自定義鍵盤已關閉!"
|
||||
"noResult" = "❗ 沒有結果!"
|
||||
"noQuery" = "❌ 未找到查詢!請重新使用命令!"
|
||||
"wentWrong" = "❌ 出了點問題!"
|
||||
"noIpRecord" = "❗ 沒有 IP 記錄!"
|
||||
"noInbounds" = "❗ 沒有找到入站連線!"
|
||||
"unlimited" = "♾ 無限制"
|
||||
"add" = "新增"
|
||||
"month" = "月"
|
||||
"months" = "月"
|
||||
"day" = "天"
|
||||
"days" = "天"
|
||||
"hours" = "小時"
|
||||
"unknown" = "未知"
|
||||
"inbounds" = "入站連線"
|
||||
"clients" = "客戶端"
|
||||
"offline" = "🔴 離線"
|
||||
"online" = "🟢 線上"
|
||||
|
||||
[tgbot.commands]
|
||||
"unknown" = "❗ 未知命令"
|
||||
"pleaseChoose" = "👇 請選擇:\r\n"
|
||||
"help" = "🤖 歡迎使用本機器人!它旨在為您提供來自伺服器的特定資料,並允許您進行必要的修改。\r\n\r\n"
|
||||
"start" = "👋 你好,<i>{{ .Firstname }}</i>。\r\n"
|
||||
"welcome" = "🤖 歡迎來到 <b>{{ .Hostname }}</b> 管理機器人。\r\n"
|
||||
"status" = "✅ 機器人正常執行!"
|
||||
"usage" = "❗ 請輸入要搜尋的文字!"
|
||||
"getID" = "🆔 您的 ID 為:<code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "要重新啟動 Xray Core:\r\n<code>/restart force</code>\r\n\r\n要搜尋客戶電子郵件:\r\n<code>/usage [電子郵件]</code>\r\n\r\n要搜尋入站(帶有客戶統計資料):\r\n<code>/inbound [備註]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "要搜尋統計資料,請使用以下命令:\r\n<code>/usage [電子郵件]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ 操作成功!"
|
||||
"restartFailed" = "❗ 操作錯誤。\r\n\r\n<code>錯誤: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core 未運行。"
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 CPU 使用率為 {{ .Percent }}%,超過閾值 {{ .Threshold }}%"
|
||||
"selectUserFailed" = "❌ 使用者選擇錯誤!"
|
||||
"userSaved" = "✅ 電報使用者已儲存。"
|
||||
"loginSuccess" = "✅ 成功登入到面板。\r\n"
|
||||
"loginFailed" = "❗️ 面板登入失敗。\r\n"
|
||||
"report" = "🕰 定時報告:{{ .RunTime }}\r\n"
|
||||
"datetime" = "⏰ 日期時間:{{ .DateTime }}\r\n"
|
||||
"hostname" = "💻 主機名:{{ .Hostname }}\r\n"
|
||||
"version" = "🚀 X-UI 版本:{{ .Version }}\r\n"
|
||||
"xrayVersion" = "📡 Xray 版本: {{ .XrayVersion }}\r\n"
|
||||
"ipv6" = "🌐 IPv6:{{ .IPv6 }}\r\n"
|
||||
"ipv4" = "🌐 IPv4:{{ .IPv4 }}\r\n"
|
||||
"ip" = "🌐 IP:{{ .IP }}\r\n"
|
||||
"ips" = "🔢 IP 地址:\r\n{{ .IPs }}\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"
|
||||
"traffic" = "🚦 流量:{{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n"
|
||||
"xrayStatus" = "ℹ️ Xray 狀態:{{ .State }}\r\n"
|
||||
"username" = "👤 使用者名稱:{{ .Username }}\r\n"
|
||||
"password" = "👤 密碼: {{ .Password }}\r\n"
|
||||
"time" = "⏰ 時間:{{ .Time }}\r\n"
|
||||
"inbound" = "📍 入站:{{ .Remark }}\r\n"
|
||||
"port" = "🔌 埠:{{ .Port }}\r\n"
|
||||
"expire" = "📅 過期日期:{{ .Time }}\r\n"
|
||||
"expireIn" = "📅 剩餘時間:{{ .Time }}\r\n"
|
||||
"active" = "💡 啟用:{{ .Enable }}\r\n"
|
||||
"enabled" = "🚨 已啟用:{{ .Enable }}\r\n"
|
||||
"online" = "🌐 連線狀態:{{ .Status }}\r\n"
|
||||
"email" = "📧 郵箱:{{ .Email }}\r\n"
|
||||
"upload" = "🔼 上傳↑:{{ .Upload }}\r\n"
|
||||
"download" = "🔽 下載↓:{{ .Download }}\r\n"
|
||||
"total" = "📊 總計:{{ .UpDown }} / {{ .Total }}\r\n"
|
||||
"TGUser" = "👤 電報使用者:{{ .TelegramID }}\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"
|
||||
"refreshedOn" = "\r\n📋🔄 重新整理時間:{{ .Time }}\r\n\r\n"
|
||||
"yes" = "✅ 是的"
|
||||
"no" = "❌ 沒有"
|
||||
|
||||
[tgbot.buttons]
|
||||
"closeKeyboard" = "❌ 關閉鍵盤"
|
||||
"cancel" = "❌ 取消"
|
||||
"cancelReset" = "❌ 取消重置"
|
||||
"cancelIpLimit" = "❌ 取消 IP 限制"
|
||||
"confirmResetTraffic" = "✅ 確認重置流量?"
|
||||
"confirmClearIps" = "✅ 確認清除 IP?"
|
||||
"confirmRemoveTGUser" = "✅ 確認移除 Telegram 使用者?"
|
||||
"confirmToggle" = "✅ 確認啟用/禁用使用者?"
|
||||
"dbBackup" = "獲取資料庫備份"
|
||||
"serverUsage" = "伺服器使用情況"
|
||||
"getInbounds" = "獲取入站資訊"
|
||||
"depleteSoon" = "即將耗盡"
|
||||
"clientUsage" = "獲取使用情況"
|
||||
"onlines" = "線上客戶端"
|
||||
"commands" = "命令"
|
||||
"refresh" = "🔄 重新整理"
|
||||
"clearIPs" = "❌ 清除 IP"
|
||||
"removeTGUser" = "❌ 移除 Telegram 使用者"
|
||||
"selectTGUser" = "👤 選擇 Telegram 使用者"
|
||||
"selectOneTGUser" = "👤 選擇一個 Telegram 使用者:"
|
||||
"resetTraffic" = "📈 重置流量"
|
||||
"resetExpire" = "📅 更改到期日期"
|
||||
"ipLog" = "🔢 IP 日誌"
|
||||
"ipLimit" = "🔢 IP 限制"
|
||||
"setTGUser" = "👤 設定 Telegram 使用者"
|
||||
"toggle" = "🔘 啟用/禁用"
|
||||
"custom" = "🔢 風俗"
|
||||
"confirmNumber" = "✅ 確認: {{ .Num }}"
|
||||
"confirmNumberAdd" = "✅ 確認新增:{{ .Num }}"
|
||||
"limitTraffic" = "🚧 流量限制"
|
||||
"getBanLogs" = "禁止日誌"
|
||||
"allClients" = "所有客戶"
|
||||
|
||||
[tgbot.answers]
|
||||
"successfulOperation" = "✅ 成功!"
|
||||
"errorOperation" = "❗ 操作錯誤。"
|
||||
"getInboundsFailed" = "❌ 獲取入站資訊失敗。"
|
||||
"getClientsFailed" = "❌ 獲取客戶失敗。"
|
||||
"canceled" = "❌ {{ .Email }}:操作已取消。"
|
||||
"clientRefreshSuccess" = "✅ {{ .Email }}:客戶端重新整理成功。"
|
||||
"IpRefreshSuccess" = "✅ {{ .Email }}:IP 重新整理成功。"
|
||||
"TGIdRefreshSuccess" = "✅ {{ .Email }}:客戶端的 Telegram 使用者重新整理成功。"
|
||||
"resetTrafficSuccess" = "✅ {{ .Email }}:流量已重置成功。"
|
||||
"setTrafficLimitSuccess" = "✅ {{ .Email }}: 流量限制儲存成功。"
|
||||
"expireResetSuccess" = "✅ {{ .Email }}:過期天數已重置成功。"
|
||||
"resetIpSuccess" = "✅ {{ .Email }}:成功儲存 IP 限制數量為 {{ .Count }}。"
|
||||
"clearIpSuccess" = "✅ {{ .Email }}:IP 已成功清除。"
|
||||
"getIpLog" = "✅ {{ .Email }}:獲取 IP 日誌。"
|
||||
"getUserInfo" = "✅ {{ .Email }}:獲取 Telegram 使用者資訊。"
|
||||
"removedTGUserSuccess" = "✅ {{ .Email }}:Telegram 使用者已成功移除。"
|
||||
"enableSuccess" = "✅ {{ .Email }}:已成功啟用。"
|
||||
"disableSuccess" = "✅ {{ .Email }}:已成功禁用。"
|
||||
"askToAddUserId" = "未找到您的配置!\r\n請向管理員詢問,在您的配置中使用您的 Telegram 使用者 ChatID。\r\n\r\n您的使用者 ChatID:<code>{{ .TgUserID }}</code>"
|
||||
"chooseClient" = "為入站 {{ .Inbound }} 選擇一個客戶"
|
||||
"chooseInbound" = "選擇一個入站"
|
||||
@@ -129,7 +129,7 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]in
|
||||
CipherType: ssCipherType,
|
||||
})
|
||||
} else {
|
||||
account = serial.ToTypedMessage(&shadowsocks_2022.User{
|
||||
account = serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
|
||||
Key: user["password"].(string),
|
||||
Email: user["email"].(string),
|
||||
})
|
||||
|
||||
@@ -14,6 +14,7 @@ type InboundConfig struct {
|
||||
StreamSettings json_util.RawMessage `json:"streamSettings"`
|
||||
Tag string `json:"tag"`
|
||||
Sniffing json_util.RawMessage `json:"sniffing"`
|
||||
Allocate json_util.RawMessage `json:"allocate"`
|
||||
}
|
||||
|
||||
func (c *InboundConfig) Equals(other *InboundConfig) bool {
|
||||
@@ -38,5 +39,8 @@ func (c *InboundConfig) Equals(other *InboundConfig) bool {
|
||||
if !bytes.Equal(c.Sniffing, other.Sniffing) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(c.Allocate, other.Allocate) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -226,6 +226,7 @@ func (p *process) Start() (err error) {
|
||||
if err != nil {
|
||||
logger.Error("Failure in running xray-core:", err)
|
||||
p.exitErr = err
|
||||
p.witeCrachReport(err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -241,3 +242,8 @@ func (p *process) Stop() error {
|
||||
}
|
||||
return p.cmd.Process.Signal(syscall.SIGTERM)
|
||||
}
|
||||
|
||||
func (p *process) witeCrachReport(err error) error {
|
||||
crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
|
||||
return os.WriteFile(crashReportPath, []byte(err.Error()), os.ModePerm)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user