Compare commits

...

19 Commits

Author SHA1 Message Date
Alireza Ahmadi
1700e85d06 Update docker.yml 2023-02-16 09:40:01 +01:00
Alireza Ahmadi
931e949442 docker workflow 2023-02-15 23:04:58 +01:00
Alireza Ahmadi
8bca416142 Ready for new version 2023-02-15 21:29:01 +01:00
Alireza Ahmadi
adf2b96f38 small github related changes 2023-02-15 20:52:01 +01:00
Alireza Ahmadi
e47ea983bd New xray settings options 2023-02-15 20:51:25 +01:00
Alireza Ahmadi
b62f747e88 Default timezone change to Tehran 2023-02-15 16:35:19 +01:00
Alireza Ahmadi
784e6e24e2 Enhanced search 2023-02-15 12:33:34 +01:00
Alireza Ahmadi
4af4aadd14 infoModal add more info 2023-02-15 12:33:13 +01:00
Alireza Ahmadi
9b3415865a SMall change in view and Readme 2023-02-15 12:21:18 +01:00
Alireza Ahmadi
8b6ea9e0d5 initiate email field for new client 2023-02-12 12:43:38 +01:00
Alireza Ahmadi
2a6f678b53 version increase to 0.2.2 2023-02-12 01:35:36 +01:00
Alireza Ahmadi
7225f00c2b revert github builder to ubuntu 18.04 2023-02-12 01:26:26 +01:00
Alireza Ahmadi
85db586d95 revert github builder to ubuntu 18.04 2023-02-12 01:24:35 +01:00
Alireza Ahmadi
2d7663f971 Merge pull request #2 from alireza0:fix-remark
Add user's email to remark if exists
Fix false reports
Fix some translations
Fix dockerfile
2023-02-11 17:50:01 +01:00
Alireza Ahmadi
c935014ba9 Increse version 2023-02-11 17:07:28 +01:00
Alireza Ahmadi
2c61b5a426 Fix dockerfile 2023-02-11 17:07:00 +01:00
Alireza Ahmadi
a5cfe4fc1e Fix in translations 2023-02-11 17:05:58 +01:00
Alireza Ahmadi
3cc3b3b04d Fix false reports 2023-02-11 17:05:35 +01:00
Alireza Ahmadi
8e550bc308 Add user's email to remark if exists 2023-02-11 14:48:02 +01:00
16 changed files with 435 additions and 179 deletions

10
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@@ -1,18 +1,12 @@
name: Docker Image CI name: Docker Image CI
on: on:
push: push:
branches: [ master ] tags:
- "*"
workflow_dispatch: workflow_dispatch:
inputs:
project:
description: 'Project'
required: true
default: ''
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -20,30 +14,42 @@ jobs:
with: with:
submodules: true submodules: true
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
alireza7/x-ui
ghcr.io/alireza0/x-ui
tags: |
type=ref,event=branch
type=ref,event=tag
type=pep440,pattern={{version}}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1
- name: Docker Hub login
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
run: |
echo "${DOCKERHUB_TOKEN}" | docker login --username ${DOCKERHUB_USERNAME} --password-stdin
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx uses: docker/setup-buildx-action@v2
uses: crazy-max/ghaction-docker-buildx@v1
with:
buildx-version: latest
- name: Build Dockerfile - name: Login to Docker Hub
env: uses: docker/login-action@v2
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} with:
DOCKERHUB_REPO: ${{ secrets.DOCKER_HUB_REPOSITORY }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
run: | password: ${{ secrets.DOCKER_HUB_TOKEN }}
docker buildx build \
--platform=linux/amd64,linux/arm64 \ - name: Login to GHCR
--output "type=image,push=true" \ uses: docker/login-action@v2
--file ./Dockerfile ./ \ with:
--tag $(echo "${DOCKERHUB_USERNAME}" | tr '[:upper:]' '[:lower:]')/${{ github.event.inputs.project }}:latest registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
platforms: linux/amd64,linux/arm64/v8
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -4,9 +4,10 @@ on:
tags: tags:
- "*" - "*"
workflow_dispatch: workflow_dispatch:
jobs: jobs:
release: release:
runs-on: ubuntu-22.04 runs-on: ubuntu-18.04
outputs: outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
steps: steps:
@@ -14,7 +15,7 @@ jobs:
id: create_release id: create_release
uses: actions/create-release@v1 uses: actions/create-release@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
tag_name: ${{ github.ref }} tag_name: ${{ github.ref }}
release_name: ${{ github.ref }} release_name: ${{ github.ref }}
@@ -23,7 +24,7 @@ jobs:
linuxamd64build: linuxamd64build:
name: build x-ui amd64 version name: build x-ui amd64 version
needs: release needs: release
runs-on: ubuntu-22.04 runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up Go - name: Set up Go
@@ -54,7 +55,7 @@ jobs:
- name: upload - name: upload
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.release.outputs.upload_url }} upload_url: ${{ needs.release.outputs.upload_url }}
asset_path: x-ui-linux-amd64.tar.gz asset_path: x-ui-linux-amd64.tar.gz
@@ -63,7 +64,7 @@ jobs:
linuxarm64build: linuxarm64build:
name: build x-ui arm64 version name: build x-ui arm64 version
needs: release needs: release
runs-on: ubuntu-22.04 runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up Go - name: Set up Go
@@ -96,7 +97,7 @@ jobs:
- name: upload - name: upload
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.release.outputs.upload_url }} upload_url: ${{ needs.release.outputs.upload_url }}
asset_path: x-ui-linux-arm64.tar.gz asset_path: x-ui-linux-arm64.tar.gz
@@ -105,7 +106,7 @@ jobs:
linuxs390xbuild: linuxs390xbuild:
name: build x-ui s390x version name: build x-ui s390x version
needs: release needs: release
runs-on: ubuntu-22.04 runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up Go - name: Set up Go
@@ -138,7 +139,7 @@ jobs:
- name: upload - name: upload
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.release.outputs.upload_url }} upload_url: ${{ needs.release.outputs.upload_url }}
asset_path: x-ui-linux-s390x.tar.gz asset_path: x-ui-linux-s390x.tar.gz

View File

@@ -7,10 +7,10 @@ RUN go build main.go
FROM alpine FROM alpine
LABEL org.opencontainers.image.authors="alireza7@gmail.com" LABEL org.opencontainers.image.authors="alireza7@gmail.com"
RUN apk add ca-certificates tzdata
ENV TZ=Asia/Tehran ENV TZ=Asia/Tehran
WORKDIR /app WORKDIR /app
RUN apk add ca-certificates tzdata && mkdir bin
COPY --from=builder /app/main /app/x-ui COPY --from=builder /app/main /app/x-ui
COPY ./bin/. /app/bin/.
VOLUME [ "/etc/x-ui" ] VOLUME [ "/etc/x-ui" ]
CMD [ "./x-ui" ] CMD [ "./x-ui" ]

View File

@@ -1,4 +1,9 @@
# x-ui # x-ui
![](https://img.shields.io/github/v/release/alireza0/x-ui.svg)
![](https://img.shields.io/docker/pulls/alireza7/x-ui.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/alireza0/x-ui)](https://goreportcard.com/report/github.com/alireza0/x-ui)
[![Downloads](https://img.shields.io/github/downloads/alireza0/x-ui/total.svg)](https://img.shields.io/github/downloads/alireza0/x-ui/total.svg)
[![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html)
> **Disclaimer: This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment** > **Disclaimer: This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment**
@@ -28,7 +33,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
- Support one-click SSL certificate application and automatic renewal - Support one-click SSL certificate application and automatic renewal
- For more advanced configuration items, please refer to the panel - For more advanced configuration items, please refer to the panel
# Inbouds picture # Screenshoot from Inbouds page
![inbounds](./media/inbounds.png) ![inbounds](./media/inbounds.png)

View File

@@ -1 +1 @@
0.2.0 0.2.3

View File

@@ -171,7 +171,7 @@ class AllSetting {
this.tgRunTime = ""; this.tgRunTime = "";
this.xrayTemplateConfig = ""; this.xrayTemplateConfig = "";
this.timeLocation = "Asia/Shanghai"; this.timeLocation = "Asia/Tehran";
if (data == null) { if (data == null) {
return return

View File

@@ -952,8 +952,7 @@ class Inbound extends XrayCommonClass {
address = this.stream.tls.server; address = this.stream.tls.server;
} }
} }
remark = this.settings.vmesses[clientIndex].email ?? remark;
let obj = { let obj = {
v: '2', v: '2',
ps: remark, ps: remark,
@@ -976,7 +975,6 @@ class Inbound extends XrayCommonClass {
const port = this.port; const port = this.port;
const type = this.stream.network; const type = this.stream.network;
const params = new Map(); const params = new Map();
remark = settings.vlesses[clientIndex].email ?? remark;
params.set("type", this.stream.network); params.set("type", this.stream.network);
if (this.xtls) { if (this.xtls) {
params.set("security", "xtls"); params.set("security", "xtls");
@@ -1061,16 +1059,27 @@ class Inbound extends XrayCommonClass {
genTrojanLink(address='', remark='', clientIndex=0) { genTrojanLink(address='', remark='', clientIndex=0) {
let settings = this.settings; let settings = this.settings;
remark = settings.trojans[clientIndex].email ?? remark;
return `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`; return `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
} }
genLink(address='', remark='', clientIndex=0) { genLink(address='', remark='', clientIndex=0) {
switch (this.protocol) { switch (this.protocol) {
case Protocols.VMESS: return this.genVmessLink(address, remark, clientIndex); case Protocols.VMESS:
case Protocols.VLESS: return this.genVLESSLink(address, remark, clientIndex); if (this.settings.vmesses[clientIndex].email != ""){
remark += '-' + this.settings.vmesses[clientIndex].email
}
return this.genVmessLink(address, remark, clientIndex);
case Protocols.VLESS:
if (this.settings.vlesses[clientIndex].email != ""){
remark += '-' + this.settings.vlesses[clientIndex].email
}
return this.genVLESSLink(address, remark, clientIndex);
case Protocols.SHADOWSOCKS: return this.genSSLink(address, remark); case Protocols.SHADOWSOCKS: return this.genSSLink(address, remark);
case Protocols.TROJAN: return this.genTrojanLink(address, remark, clientIndex); case Protocols.TROJAN:
if (this.settings.trojans[clientIndex].email != ""){
remark += '-' + this.settings.trojans[clientIndex].email
}
return this.genTrojanLink(address, remark, clientIndex);
default: return ''; default: return '';
} }
} }
@@ -1188,7 +1197,7 @@ Inbound.VmessSettings = class extends Inbound.Settings {
} }
}; };
Inbound.VmessSettings.Vmess = class extends XrayCommonClass { Inbound.VmessSettings.Vmess = class extends XrayCommonClass {
constructor(id=RandomUtil.randomUUID(), alterId=0, email='', totalGB=0, expiryTime='') { constructor(id=RandomUtil.randomUUID(), alterId=0, email=RandomUtil.randomText(), totalGB=0, expiryTime='') {
super(); super();
this.id = id; this.id = id;
this.alterId = alterId; this.alterId = alterId;
@@ -1270,7 +1279,7 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
}; };
Inbound.VLESSSettings.VLESS = class extends XrayCommonClass { Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
constructor(id=RandomUtil.randomUUID(), flow=FLOW_CONTROL.DIRECT, email='', totalGB=0, expiryTime='') { constructor(id=RandomUtil.randomUUID(), flow=FLOW_CONTROL.DIRECT, email=RandomUtil.randomText(), totalGB=0, expiryTime='') {
super(); super();
this.id = id; this.id = id;
this.flow = flow; this.flow = flow;
@@ -1384,7 +1393,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
} }
}; };
Inbound.TrojanSettings.Trojan = class extends XrayCommonClass { Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
constructor(password=RandomUtil.randomSeq(10), flow=FLOW_CONTROL.DIRECT, email='', totalGB=0, expiryTime='') { constructor(password=RandomUtil.randomSeq(10), flow=FLOW_CONTROL.DIRECT, email=RandomUtil.randomText(), totalGB=0, expiryTime='') {
super(); super();
this.password = password; this.password = password;
this.flow = flow; this.flow = flow;

View File

@@ -136,6 +136,16 @@ class RandomUtil {
return (c === 'x' ? r : (r & 0x7 | 0x8)).toString(16); return (c === 'x' ? r : (r & 0x7 | 0x8)).toString(16);
}); });
} }
static randomText() {
var chars = 'abcdefghijklmnopqrstuvwxyz1234567890';
var string = '';
var len = 6 + Math.floor(Math.random() * 5)
for(var ii=0; ii<len; ii++){
string += chars[Math.floor(Math.random() * chars.length)];
}
return string;
}
} }
class ObjectUtil { class ObjectUtil {

View File

@@ -6,26 +6,26 @@
<a-menu> <a-menu>
<a-menu-item v-if="record.hasLink()" @click="showQrcode(record,index);"><a-icon type="qrcode"></a-icon>{{ i18n "qrCode" }}</a-menu-item> <a-menu-item v-if="record.hasLink()" @click="showQrcode(record,index);"><a-icon type="qrcode"></a-icon>{{ i18n "qrCode" }}</a-menu-item>
<a-menu-item @click="showInfo(record,index);"><a-icon type="info-circle"></a-icon>{{ i18n "info" }}</a-menu-item> <a-menu-item @click="showInfo(record,index);"><a-icon type="info-circle"></a-icon>{{ i18n "info" }}</a-menu-item>
<a-menu-item @click="resetClientTraffic(client,record,$event)"><a-icon type="retweet"></a-icon>{{ i18n "pages.inbounds.resetTraffic" }}</a-menu-item> <a-menu-item @click="resetClientTraffic(client,record,$event)" v-if="client.email != ''"><a-icon type="retweet"></a-icon>{{ i18n "pages.inbounds.resetTraffic" }}</a-menu-item>
</a-menu> </a-menu>
</template> </template>
</a-dropdown> </a-dropdown>
</template> </template>
<template slot="client" slot-scope="text, client"> <template slot="client" slot-scope="text, client">
[[ client.email ]] [[ client.email ]]
<a-tag v-if="!isClientEnabled(record, client.email)" color="red"> expired</a-tag> <a-tag v-if="!isClientEnabled(record, client.email)" color="red">{{ i18n "disabled" }}</a-tag>
</template> </template>
<template slot="traffic" slot-scope="text, client"> <template slot="traffic" slot-scope="text, client">
<a-tag v-if="client._totalGB === 0" color="blue">{{ i18n "usage" }}: [[ sizeFormat(getUpStats(record, client.email) + getDownStats(record, client.email)) ]]</a-tag> <a-tag color="blue">[[ sizeFormat(getUpStats(record, client.email)) ]] / [[ sizeFormat(getDownStats(record, client.email)) ]]</a-tag>
<a-tag v-if="client._totalGB > 0 && !isTrafficExhausted(record, client.email)" color="green">{{ i18n "usage" }}: [[ sizeFormat(getUpStats(record, client.email) + getDownStats(record, client.email)) ]] / [[client._totalGB]]GB</a-tag> <template v-if="client._totalGB > 0">
<a-tag v-if="client._totalGB > 0 && isTrafficExhausted(record, client.email)" color="red">{{ i18n "usage" }}: [[ sizeFormat(getUpStats(record, client.email) + getDownStats(record, client.email)) ]] / [[client._totalGB]]GB</a-tag> <a-tag v-if="isTrafficExhausted(record, client.email)" color="red">[[client._totalGB]]GB</a-tag>
<a-tag v-else color="cyan">[[client._totalGB]]GB</a-tag>
</template>
<a-tag v-else color="green">{{ i18n "indefinite" }}</a-tag>
</template> </template>
<template slot="expiryTime" slot-scope="text, client, index"> <template slot="expiryTime" slot-scope="text, client, index">
<template v-if="client._expiryTime > 0"> <template v-if="client._expiryTime > 0">
<a-tag v-if="isExpiry(record, index)" color="red"> <a-tag :color="isExpiry(record, index)? 'red' : 'blue'">
[[ DateUtil.formatMillis(client._expiryTime) ]]
</a-tag>
<a-tag v-else color="blue">
[[ DateUtil.formatMillis(client._expiryTime) ]] [[ DateUtil.formatMillis(client._expiryTime) ]]
</a-tag> </a-tag>
</template> </template>

View File

@@ -1,9 +1,11 @@
{{define "inboundInfoModal"}} {{define "inboundInfoModal"}}
<a-modal id="inbound-info-modal" v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}' <a-modal id="inbound-info-modal"
:closable="true" v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}'
:mask-closable="true" :closable="true"
:footer="null" :mask-closable="true"
> :footer="null"
width="600px"
>
<table style="margin-bottom: 10px; width: 100%;"> <table style="margin-bottom: 10px; width: 100%;">
<tr><td> <tr><td>
<table> <table>
@@ -55,11 +57,47 @@
</tr> </tr>
</table> </table>
<a-divider>{{ i18n "pages.inbounds.client" }}</a-divider> <a-divider>{{ i18n "pages.inbounds.client" }}</a-divider>
<template v-if="dbInbound.hasLink()"> <table style="margin-bottom: 10px; width: 100%;">
<p>Client URL:</p> <tr><th>[[ Object.keys(infoModal.clientSettings)[0] ]]</th><th>[[ Object.keys(infoModal.clientSettings)[1] ]]</th><th>[[ Object.keys(infoModal.clientSettings)[2] ]]</th></tr>
<tr>
<td><a-tag color="green">[[ Object.values(infoModal.clientSettings)[0] ]]</a-tag></td>
<td><a-tag color="green">[[ Object.values(infoModal.clientSettings)[1] ]]</a-tag></td>
<td><a-tag color="green">[[ Object.values(infoModal.clientSettings)[2] ]]</a-tag></td>
</tr>
</table>
<table style="margin-bottom: 10px; width: 100%;">
<tr><th>{{ i18n "usage" }}</th><th>{{ i18n "pages.inbounds.totalFlow" }}</th><th>{{ i18n "pages.inbounds.expireDate" }}</th><th>{{ i18n "enable" }}</th></tr>
<tr>
<td>
<a-tag :color="statsColor(infoModal.clientStats)">
[[ sizeFormat(infoModal.clientStats['up']) ]] /
[[ sizeFormat(infoModal.clientStats['down']) ]]
([[ sizeFormat(infoModal.clientStats['up'] + infoModal.clientStats['down']) ]])
</a-tag>
</td>
<td>
<a-tag v-if="infoModal.clientSettings.totalGB > 0" :color="statsColor(infoModal.clientStats)">[[ sizeFormat(infoModal.clientSettings.totalGB) ]]</a-tag>
<a-tag v-else color="green">{{ i18n "indefinite" }}</a-tag>
</td>
<td>
<template v-if="infoModal.clientSettings.expiryTime > 0">
<a-tag :color="infoModal.isExpired ? 'red' : 'blue'">
[[ DateUtil.formatMillis(infoModal.clientSettings.expiryTime) ]]
</a-tag>
</template>
<a-tag v-else color="green">{{ i18n "indefinite" }}</a-tag>
</td>
<td>
<a-tag v-if="infoModal.clientStats.enable" color="blue">{{ i18n "enabled" }}</a-tag>
<a-tag v-else color="red">{{ i18n "disabled" }}</a-tag>
</td>
</tr>
</table>
<div v-if="dbInbound.hasLink()">
<a-divider>URL</a-divider>
<p>[[ infoModal.link ]]</p> <p>[[ infoModal.link ]]</p>
<button class="btn" id="copy-url-link"><a-icon type="snippets"></a-icon>{{ i18n "copy" }}</button> <button class="ant-btn ant-btn-primary" id="copy-url-link"><a-icon type="snippets"></a-icon>{{ i18n "copy" }}</button>
</template> </div>
</a-modal> </a-modal>
<script> <script>
@@ -67,14 +105,32 @@
visible: false, visible: false,
inbound: new Inbound(), inbound: new Inbound(),
dbInbound: new DBInbound(), dbInbound: new DBInbound(),
clientSettings: new Inbound.Settings(),
clientStats: [],
upStats: 0,
downStats: 0,
clipboard: null, clipboard: null,
link: null, link: null,
index: 0, index: 0,
isExpired: false,
show(dbInbound, index=0) { show(dbInbound, index=0) {
this.index = index; this.index = index;
this.inbound = dbInbound.toInbound(); this.inbound = dbInbound.toInbound();
this.dbInbound = new DBInbound(dbInbound); this.dbInbound = new DBInbound(dbInbound);
this.link = dbInbound.genLink(index); this.link = dbInbound.genLink(index);
this.clientSettings = Object.values(JSON.parse(this.inbound.settings).clients)[index];
this.clientStats = dbInbound.clientStats;
this.isExpired = this.inbound.isExpiry(index);
if(dbInbound.clientStats.length > 0)
{
for (const key in dbInbound.clientStats) {
if (Object.hasOwnProperty.call(dbInbound.clientStats, key)) {
if(dbInbound.clientStats[key]['email'] == this.clientSettings.email)
this.clientStats = dbInbound.clientStats[key];
}
}
}
this.visible = true; this.visible = true;
infoModalApp.$nextTick(() => { infoModalApp.$nextTick(() => {
if (this.clipboard === null) { if (this.clipboard === null) {
@@ -120,6 +176,11 @@
app.$message.success('{{ i18n "copied" }}') app.$message.success('{{ i18n "copied" }}')
this.infoModal.clipboard.destroy(); this.infoModal.clipboard.destroy();
}); });
},
statsColor(stats) {
if(stats['total'] === 0) return 'blue'
else if(stats['total'] > 0 && (stats['down']+stats['up']) < stats['total']) return 'cyan'
else return 'red'
} }
}, },

View File

@@ -196,18 +196,18 @@
}]; }];
const innerColumns = [ const innerColumns = [
{ title: '', width: 50, scopedSlots: { customRender: 'actions' } }, { title: '', width: 20, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } }, { title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 100, scopedSlots: { customRender: 'traffic' } }, { title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 80, scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 80, scopedSlots: { customRender: 'expiryTime' } }, { title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
{ title: 'UID', width: 150, dataIndex: "id" }, { title: 'UID', width: 150, dataIndex: "id" },
]; ];
const innerTrojanColumns = [ const innerTrojanColumns = [
{ title: '', width: 50, scopedSlots: { customRender: 'actions' } }, { title: '', width: 20, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } }, { title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 100, scopedSlots: { customRender: 'traffic' } }, { title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 80, scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 80, scopedSlots: { customRender: 'expiryTime' } }, { title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
{ title: 'Password', width: 150, dataIndex: "password" }, { title: 'Password', width: 150, dataIndex: "password" },
]; ];
@@ -257,7 +257,18 @@
this.searchedInbounds.splice(0, this.searchedInbounds.length); this.searchedInbounds.splice(0, this.searchedInbounds.length);
this.dbInbounds.forEach(inbound => { this.dbInbounds.forEach(inbound => {
if (ObjectUtil.deepSearch(inbound, key)) { if (ObjectUtil.deepSearch(inbound, key)) {
this.searchedInbounds.push(inbound); const newInbound = new DBInbound(inbound);
const inboundSettings = JSON.parse(inbound.settings);
if (inboundSettings.hasOwnProperty('clients')){
const searchedSettings = { "clients": [] };
inboundSettings.clients.forEach(client => {
if (ObjectUtil.deepSearch(client, key)){
searchedSettings.clients.push(client);
}
});
newInbound.settings = Inbound.Settings.fromJson(inbound.protocol, searchedSettings);
}
this.searchedInbounds.push(newInbound);
} }
}); });
} }
@@ -475,6 +486,9 @@
} }
} }
} }
else{
return true
}
}, },
}, },
watch: { watch: {

View File

@@ -87,13 +87,28 @@
style="max-width: 300px"></a-input> style="max-width: 300px"></a-input>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<!-- <a-button type="primary" @click="updateUser">修改</a-button>--> <!-- <a-button type="primary" @click="updateUser">Revise</a-button>-->
<a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button> <a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'> <a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'>
<a-list item-layout="horizontal" style="background: white"> <a-list item-layout="horizontal" style="background: white">
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigTorrent"}}' desc='{{ i18n "pages.setting.xrayConfigTorrentDesc"}}' v-model="torrentSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.setting.xrayConfigPrivateIp"}}' desc='{{ i18n "pages.setting.xrayConfigPrivateIpDesc"}}' v-model="privateIpSettings"></setting-list-item>
<a-divider>{{ i18n "pages.setting.advancedTemplate"}}</a-divider>
<a-collapse>
<a-collapse-panel header="{{ i18n "pages.setting.xrayConfigInbounds"}}">
<setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigInbounds"}}' desc='{{ i18n "pages.setting.xrayConfigInboundsDesc"}}' v-model ="inboundSettings"></setting-list-item>
</a-collapse-panel>
<a-collapse-panel header="{{ i18n "pages.setting.xrayConfigOutbounds"}}">
<setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigOutbounds"}}' desc='{{ i18n "pages.setting.xrayConfigOutboundsDesc"}}' v-model ="outboundSettings"></setting-list-item>
</a-collapse-panel>
<a-collapse-panel header="{{ i18n "pages.setting.xrayConfigRoutings"}}">
<setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigRoutings"}}' desc='{{ i18n "pages.setting.xrayConfigRoutingsDesc"}}' v-model ="routingRuleSettings"></setting-list-item>
</a-collapse-panel>
</a-collapse>
<a-divider>{{ i18n "pages.setting.completeTemplate"}}</a-divider>
<setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigTemplate"}}' desc='{{ i18n "pages.setting.xrayConfigTemplateDesc"}}' v-model="allSetting.xrayTemplateConfig"></setting-list-item> <setting-list-item type="textarea" title='{{ i18n "pages.setting.xrayConfigTemplate"}}' desc='{{ i18n "pages.setting.xrayConfigTemplateDesc"}}' v-model="allSetting.xrayTemplateConfig"></setting-list-item>
</a-list> </a-list>
</a-tab-pane> </a-tab-pane>
@@ -189,6 +204,102 @@
this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting); this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting);
} }
}, },
computed: {
templateSettings: {
get: function () { return this.allSetting.xrayTemplateConfig ? JSON.parse(this.allSetting.xrayTemplateConfig) : null ; },
set: function (newValue) { this.allSetting.xrayTemplateConfig = JSON.stringify(newValue, null, 2) },
},
inboundSettings: {
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.inbounds, null, 2) : null; },
set: function (newValue) {
newTemplateSettings = this.templateSettings;
newTemplateSettings.inbounds = JSON.parse(newValue)
this.templateSettings = newTemplateSettings
},
},
outboundSettings: {
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.outbounds, null, 2) : null; },
set: function (newValue) {
newTemplateSettings = this.templateSettings;
newTemplateSettings.outbounds = JSON.parse(newValue)
this.templateSettings = newTemplateSettings
},
},
routingRuleSettings: {
get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.routing.rules, null, 2) : null; },
set: function (newValue) {
newTemplateSettings = this.templateSettings;
newTemplateSettings.routing.rules = JSON.parse(newValue)
this.templateSettings = newTemplateSettings
},
},
torrentSettings: {
get: function () {
torrentFilter = false
if(this.templateSettings != null){
this.templateSettings.routing.rules.forEach(routingRule => {
if(routingRule.hasOwnProperty("protocol")){
if (routingRule.protocol[0] === "bittorrent" && routingRule.outboundTag == "blocked"){
torrentFilter = true
}
}
});
}
return torrentFilter
},
set: function (newValue) {
newTemplateSettings = JSON.parse(this.allSetting.xrayTemplateConfig);
if (newValue){
newTemplateSettings.routing.rules.push(JSON.parse("{\"outboundTag\": \"blocked\",\"protocol\": [\"bittorrent\"],\"type\": \"field\"}"))
}
else {
newTemplateSettings.routing.rules = [];
this.templateSettings.routing.rules.forEach(routingRule => {
if (routingRule.hasOwnProperty('protocol')){
if (routingRule.protocol[0] === "bittorrent" && routingRule.outboundTag == "blocked"){
return;
}
}
newTemplateSettings.routing.rules.push(routingRule);
});
}
this.templateSettings = newTemplateSettings
},
},
privateIpSettings: {
get: function () {
localIpFilter = false
if(this.templateSettings != null){
this.templateSettings.routing.rules.forEach(routingRule => {
if(routingRule.hasOwnProperty("ip")){
if (routingRule.ip[0] === "geoip:private" && routingRule.outboundTag == "blocked"){
localIpFilter = true
}
}
});
}
return localIpFilter
},
set: function (newValue) {
newTemplateSettings = JSON.parse(this.allSetting.xrayTemplateConfig);
if (newValue){
newTemplateSettings.routing.rules.push(JSON.parse("{\"outboundTag\": \"blocked\",\"ip\": [\"geoip:private\"],\"type\": \"field\"}"))
}
else {
newTemplateSettings.routing.rules = [];
this.templateSettings.routing.rules.forEach(routingRule => {
if (routingRule.hasOwnProperty('ip')){
if (routingRule.ip[0] === "geoip:private" && routingRule.outboundTag == "blocked"){
return;
}
}
newTemplateSettings.routing.rules.push(routingRule);
});
}
this.templateSettings = newTemplateSettings
},
},
}
}); });
</script> </script>

View File

@@ -1,48 +1,48 @@
"username" = "username" "username" = "Username"
"password" = "password" "password" = "Password"
"login" = "login" "login" = "Login"
"confirm" = "confirm" "confirm" = "Confirm"
"cancel" = "cancel" "cancel" = "Cancel"
"close" = "close" "close" = "Close"
"copy" = "copy" "copy" = "Copy"
"copied" = "copied" "copied" = "Copied"
"download" = "download" "download" = "Download"
"remark" = "remark" "remark" = "Remark"
"enable" = "enable" "enable" = "Enable"
"protocol" = "protocol" "protocol" = "Protocol"
"search" = "search" "search" = "Search"
"loading" = "Loading" "loading" = "Loading"
"second" = "second" "second" = "Second"
"minute" = "minute" "minute" = "Minute"
"hour" = "hour" "hour" = "Hour"
"day" = "day" "day" = "Day"
"check" = "check" "check" = "Check"
"indefinite" = "indefinite" "indefinite" = "Indefinite"
"unlimited" = "unlimited" "unlimited" = "Unlimited"
"none" = "none" "none" = "None"
"qrCode" = "QR Code" "qrCode" = "QR Code"
"info" = "More information" "info" = "More information"
"edit" = "edit" "edit" = "Edit"
"delete" = "delete" "delete" = "Delete"
"reset" = "reset" "reset" = "Reset"
"copySuccess" = "Copy successfully" "copySuccess" = "Copy successfully"
"sure" = "Sure" "sure" = "Sure"
"encryption" = "encryption" "encryption" = "Encryption"
"transmission" = "transmission" "transmission" = "Transmission"
"host" = "host" "host" = "Host"
"path" = "path" "path" = "Path"
"camouflage" = "camouflage" "camouflage" = "Camouflage"
"enabled" = "enabled" "enabled" = "Enabled"
"disabled" = "disabled" "disabled" = "Disabled"
"domainName" = "domain name" "domainName" = "Domain name"
"additional" = "alter" "additional" = "Alter"
"monitor" = "Listen IP" "monitor" = "Listen IP"
"certificate" = "certificat" "certificate" = "Certificat"
"fail" = "fail" "fail" = "Fail"
"success" = " success" "success" = " Success"
"getVersion" = "get version" "getVersion" = "Get version"
"install" = "install" "install" = "Install"
"clients" = "Clients" "clients" = "Clients"
"usage" = "Usage" "usage" = "Usage"
@@ -64,11 +64,10 @@
"wrongUsernameOrPassword" = "Invalid username or password" "wrongUsernameOrPassword" = "Invalid username or password"
"successLogin" = "Login" "successLogin" = "Login"
[pages.index] [pages.index]
"title" = "system status" "title" = "System status"
"memory" = "memory" "memory" = "Memory"
"hard" = "hard disk" "hard" = "Hard disk"
"xrayStatus" = "xray Status" "xrayStatus" = "xray Status"
"xraySwitch" = "Switch Version" "xraySwitch" = "Switch Version"
"xraySwitchClick" = "Click on the version you want to switch" "xraySwitchClick" = "Click on the version you want to switch"
@@ -82,27 +81,26 @@
"downSpeed" = "Total download speed for all network cards" "downSpeed" = "Total download speed for all network cards"
"totalSent" = "Total upload traffic of all network cards since system startup" "totalSent" = "Total upload traffic of all network cards since system startup"
"totalReceive" = "Total download traffic of all network cards since system startup" "totalReceive" = "Total download traffic of all network cards since system startup"
"xraySwitchVersionDialog" = "switch xray version" "xraySwitchVersionDialog" = "Switch xray version"
"xraySwitchVersionDialogDesc" = "whether to switch the xray version to" "xraySwitchVersionDialogDesc" = "Whether to switch the xray version to"
"dontRefreshh" = "Installation is in progress, please do not refresh this page" "dontRefreshh" = "Installation is in progress, please do not refresh this page"
[pages.inbounds] [pages.inbounds]
"title" = "Inbounds" "title" = "Inbounds"
"totalDownUp" = "Total uploads/downloads" "totalDownUp" = "Total uploads/downloads"
"totalUsage" = "Total usage" "totalUsage" = "Total usage"
"inboundCount" = "Number of inbound" "inboundCount" = "Number of inbound"
"operate" = "operate" "operate" = "Operate"
"enable" = "enable" "enable" = "Enable"
"remark" = "remark" "remark" = "Remark"
"protocol" = "protocol" "protocol" = "Protocol"
"port" = "port" "port" = "Port"
"traffic" = "traffic" "traffic" = "Traffic"
"details" = "details" "details" = "Details"
"transportConfig" = "transport config" "transportConfig" = "Transport config"
"expireDate" = "expire date" "expireDate" = "Expire date"
"resetTraffic" = "reset traffic" "resetTraffic" = "Reset traffic"
"addInbound" = "addInbound" "addInbound" = "Add Inbound"
"addTo" = "Add To" "addTo" = "Add To"
"revise" = "Revise" "revise" = "Revise"
"modifyInbound" = "Modify InBound" "modifyInbound" = "Modify InBound"
@@ -110,45 +108,44 @@
"deleteInboundContent" = "Are you sure you want to delete inbound?" "deleteInboundContent" = "Are you sure you want to delete inbound?"
"resetTrafficContent" = "Are you sure you want to reset traffic?" "resetTrafficContent" = "Are you sure you want to reset traffic?"
"copyLink" = "Copy Link" "copyLink" = "Copy Link"
"address" = "address" "address" = "Address"
"network" = "network" "network" = "Network"
"destinationPort" = "destination port" "destinationPort" = "Destination port"
"targetAddress" = "target address" "targetAddress" = "Target address"
"disableInsecureEncryption" = "Disable insecure encryption" "disableInsecureEncryption" = "Disable insecure encryption"
"monitorDesc" = "Leave blank by default" "monitorDesc" = "Leave blank by default"
"meansNoLimit" = "means no limit" "meansNoLimit" = "Means no limit"
"totalFlow" = "total flow" "totalFlow" = "Total flow"
"leaveBlankToNeverExpire" = "Leave blank to never expire" "leaveBlankToNeverExpire" = "Leave blank to never expire"
"noRecommendKeepDefault" = "There are no special requirements to keep the default" "noRecommendKeepDefault" = "There are no special requirements to keep the default"
"certificatePath" = "certificate file path" "certificatePath" = "Certificate file path"
"certificateContent" = "certificate file content" "certificateContent" = "Certificate file content"
"publicKeyPath" = "public key file path" "publicKeyPath" = "Public key file path"
"publicKeyContent" = "public key content" "publicKeyContent" = "Public key content"
"keyPath" = "key file path" "keyPath" = "Key file path"
"keyContent" = "key content" "keyContent" = "Key content"
"clickOnQRcode" = "click on QR Code to Copy" "clickOnQRcode" = "Click on QR Code to Copy"
"client" = "Client" "client" = "Client"
[pages.inbounds.toasts] [pages.inbounds.toasts]
"obtain" = "Obtain" "obtain" = "Obtain"
[pages.inbounds.stream.general] [pages.inbounds.stream.general]
"requestHeader" = "request header" "requestHeader" = "Request header"
"name" = "name" "name" = "Name"
"value" = "value" "value" = "Value"
[pages.inbounds.stream.tcp] [pages.inbounds.stream.tcp]
"requestVersion" = "request version" "requestVersion" = "Request version"
"requestMethod" = "request method" "requestMethod" = "Request method"
"requestPath" = "request path" "requestPath" = "Request path"
"responseVersion" = "response version" "responseVersion" = "Response version"
"responseStatus" = "response status" "responseStatus" = "Response status"
"responseStatusDescription" = "response status description" "responseStatusDescription" = "Response status description"
"responseHeader" = "response header" "responseHeader" = "Response header"
[pages.inbounds.stream.quic] [pages.inbounds.stream.quic]
"encryption" = "encryption" "encryption" = "Encryption"
[pages.setting] [pages.setting]
"title" = "Setting" "title" = "Setting"
@@ -174,8 +171,20 @@
"currentPassword" = "Current Password" "currentPassword" = "Current Password"
"newUsername" = "New Username" "newUsername" = "New Username"
"newPassword" = "New Password" "newPassword" = "New Password"
"xrayConfigTemplate" = "xray Configuration Template" "advancedTemplate" = "Advanced template parts"
"xrayConfigTemplateDesc" = "Generate the final xray configuration file based on this template, restart the panel to take effect" "completeTemplate" = "Complete template of Xray configuration"
"xrayConfigTemplate" = "Xray Configuration Template"
"xrayConfigTemplateDesc" = "Generate the final xray configuration file based on this template, restart the panel to take effect."
"xrayConfigTorrent" = "Ban bittorrent usage"
"xrayConfigTorrentDesc" = "Change the configuration temlate to avoid using bittorrent by users, restart the panel to take effect"
"xrayConfigPrivateIp" = "Ban private ip range to connect"
"xrayConfigPrivateIpDesc" = "Change the configuration temlate to avoid connecting with private IP ranges, restart the panel to take effect"
"xrayConfigInbounds" = "Configuration of Inbounds"
"xrayConfigInboundsDesc" = "Change the configuration temlate to accept special clients, restart the panel to take effect"
"xrayConfigOutbounds" = "Configuration of Outbounds"
"xrayConfigOutboundsDesc" = "Change the configuration temlate to define outgoing ways for this server, restart the panel to take effect"
"xrayConfigRoutings" = "Configuration of Routing rules"
"xrayConfigRoutingsDesc" = "Change the configuration temlate to define Routing rules for this server, restart the panel to take effect"
"telegramBotEnable" = "Enable telegram bot" "telegramBotEnable" = "Enable telegram bot"
"telegramBotEnableDesc" = "Restart the panel to take effect" "telegramBotEnableDesc" = "Restart the panel to take effect"
"telegramToken" = "Telegram Token" "telegramToken" = "Telegram Token"
@@ -188,8 +197,8 @@
"timeZoneDesc" = "The scheduled task runs according to the time in the time zone, and restarts the panel to take effect" "timeZoneDesc" = "The scheduled task runs according to the time in the time zone, and restarts the panel to take effect"
[pages.setting.toasts] [pages.setting.toasts]
"modifySetting" = "modify setting" "modifySetting" = "Modify setting"
"getSetting" = "get setting" "getSetting" = "Get setting"
"modifyUser" = "modify user" "modifyUser" = "Modify user"
"originalUserPassIncorrect" = "The original user name or original password is incorrect" "originalUserPassIncorrect" = "The original user name or original password is incorrect"
"userPassMustBeNotEmpty" = "New username and new password cannot be empty" "userPassMustBeNotEmpty" = "New username and new password cannot be empty"

View File

@@ -34,7 +34,7 @@
"path" = "مسیر" "path" = "مسیر"
"camouflage" = "استتار" "camouflage" = "استتار"
"enabled" = "فعال" "enabled" = "فعال"
"disabled" = "disabled" "disabled" = "غیرفعال"
"domainName" = "آدرس دامنه" "domainName" = "آدرس دامنه"
"additional" = "آی دی جایگزین" "additional" = "آی دی جایگزین"
"monitor" = "آی پی اتصال" "monitor" = "آی پی اتصال"
@@ -48,7 +48,7 @@
[menu] [menu]
"dashboard" = "وضعیت سیستم" "dashboard" = "وضعیت سیستم"
"inbounds" = "سروریس ها" "inbounds" = "سرویس ها"
"setting" = "تنظیمات پنل" "setting" = "تنظیمات پنل"
"logout" = "خروج" "logout" = "خروج"
"link" = "دیگر" "link" = "دیگر"
@@ -64,7 +64,6 @@
"wrongUsernameOrPassword" = "نام کاربری و رمز عبور اشتباه میباشد" "wrongUsernameOrPassword" = "نام کاربری و رمز عبور اشتباه میباشد"
"successLogin" = "خوش آمدید" "successLogin" = "خوش آمدید"
[pages.index] [pages.index]
"title" = "وضعیت سیستم" "title" = "وضعیت سیستم"
"memory" = "حافظه رم" "memory" = "حافظه رم"
@@ -86,7 +85,6 @@
"xraySwitchVersionDialogDesc" = "آیا از تغییر ورژن مطمئن هستین" "xraySwitchVersionDialogDesc" = "آیا از تغییر ورژن مطمئن هستین"
"dontRefreshh" = "در حال نصب ، لطفا رفرش نکنید " "dontRefreshh" = "در حال نصب ، لطفا رفرش نکنید "
[pages.inbounds] [pages.inbounds]
"title" = "کاربران" "title" = "کاربران"
"totalDownUp" = "جمع آپلود/دانلود" "totalDownUp" = "جمع آپلود/دانلود"
@@ -149,7 +147,6 @@
[pages.inbounds.stream.quic] [pages.inbounds.stream.quic]
"encryption" = "رمزنگاری" "encryption" = "رمزنگاری"
[pages.setting] [pages.setting]
"title" = "تنظیمات" "title" = "تنظیمات"
"save" = "ذخیره" "save" = "ذخیره"
@@ -174,8 +171,20 @@
"currentPassword" = "رمز عبور فعلی" "currentPassword" = "رمز عبور فعلی"
"newUsername" = "نام کاربری جدید" "newUsername" = "نام کاربری جدید"
"newPassword" = "رمز عبور جدید" "newPassword" = "رمز عبور جدید"
"xrayConfigTemplate" = "تنظیمات قالب Xray" "advancedTemplate" = "بخش های پیشرفته الگو"
"xrayConfigTemplateDesc" = "فایل پیکربندی xray نهایی را بر اساس این الگو ایجاد کنید. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید! پنل را مجدداً راه اندازی کنید تا اعمال شود" "completeTemplate" = "الگوی کامل تنظیمات ایکس ری"
"xrayConfigTemplate" = "تنظیمات الگو ایکس ری"
"xrayConfigTemplateDesc" = "فایل پیکربندی ایکس ری نهایی بر اساس این الگو ایجاد میشود. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید! پنل را مجدداً راه اندازی کنید تا اعمال شود"
"xrayConfigTorrent" = "فیلتر کردن بیت تورنت"
"xrayConfigTorrentDesc" = "الگوی تنظیمات را برای فیلتر کردن پروتکل بیت تورنت برای کاربران تغییر میدهد. پنل را مجدداً راه اندازی کنید تا اعمال شود"
"xrayConfigPrivateIp" = "جلوگیری از اتصال آی پی های نامعتبر"
"xrayConfigPrivateIpDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال آی پی های نامعتبر و بسته های سرگردان تغییر میدهد. پنل را مجدداً راه اندازی کنید تا اعمال شود"
"xrayConfigInbounds" = "تنظیمات ورودی"
"xrayConfigInboundsDesc" = "میتوانید الگوی تنظیمات را برای ورودی های خاص تنظیم نمایید. پنل را مجدداً راه اندازی کنید تا اعمال شود"
"xrayConfigOutbounds" = "تنظیمات خروجی"
"xrayConfigOutboundsDesc" = "میتوانید الگوی تنظیمات را برای خروجی اینترنت تنظیم نمایید. پنل را مجدداً راه اندازی کنید تا اعمال شود"
"xrayConfigRoutings" = "تنظیمات قوانین مسیریابی"
"xrayConfigRoutingsDesc" = "میتوانید الگوی تنظیمات را برای مسیریابی تنظیم نمایید. پنل را مجدداً راه اندازی کنید تا اعمال شود"
"telegramBotEnable" = "فعالسازی ربات تلگرام" "telegramBotEnable" = "فعالسازی ربات تلگرام"
"telegramBotEnableDesc" = "پنل را مجدداً راه اندازی کنید تا اعمال شود" "telegramBotEnableDesc" = "پنل را مجدداً راه اندازی کنید تا اعمال شود"
"telegramToken" = "توکن تلگرام" "telegramToken" = "توکن تلگرام"

View File

@@ -44,6 +44,7 @@
"getVersion" = "获取版本" "getVersion" = "获取版本"
"install" = "安装" "install" = "安装"
"clients" = "客户端" "clients" = "客户端"
"usage" = "用法"
[menu] [menu]
"dashboard" = "系统状态" "dashboard" = "系统状态"
@@ -84,7 +85,6 @@
"xraySwitchVersionDialogDesc" = "是否切换 xray 版本至" "xraySwitchVersionDialogDesc" = "是否切换 xray 版本至"
"dontRefreshh" = "安装中,请不要刷新此页面" "dontRefreshh" = "安装中,请不要刷新此页面"
[pages.inbounds] [pages.inbounds]
"title" = "入站列表" "title" = "入站列表"
"totalDownUp" = "总上传 / 下载" "totalDownUp" = "总上传 / 下载"
@@ -124,7 +124,8 @@
"publicKeyContent" = "公钥内容" "publicKeyContent" = "公钥内容"
"keyPath" = "密钥文件路径" "keyPath" = "密钥文件路径"
"keyContent" = "密钥内容" "keyContent" = "密钥内容"
"clickOnQRcode" = "click on QR Code to Copy" "clickOnQRcode" = "点击二维码复制"
"client" = "客户"
[pages.inbounds.toasts] [pages.inbounds.toasts]
"obtain" = "获取" "obtain" = "获取"
@@ -146,7 +147,6 @@
[pages.inbounds.stream.quic] [pages.inbounds.stream.quic]
"encryption" = "加密" "encryption" = "加密"
[pages.setting] [pages.setting]
"title" = "设置" "title" = "设置"
"save" = "保存配置" "save" = "保存配置"
@@ -171,8 +171,20 @@
"currentPassword" = "原密码" "currentPassword" = "原密码"
"newUsername" = "新用户名" "newUsername" = "新用户名"
"newPassword" = "新密码" "newPassword" = "新密码"
"xrayConfigTemplate" = "xray 配置模版" "advancedTemplate" = "高级模板部件"
"xrayConfigTemplateDesc" = "以该模版为基础生成最终的 xray 配置文件,重启面板生效" "completeTemplate" = "Xray 配置的完整模板"
"xrayConfigTemplate" = "xray 配置模板"
"xrayConfigTemplateDesc" = "以该模型为基础生成最终的xray配置文件重新启动面板生成效率"
"xrayConfigTorrent" = "禁止使用 bittorrent"
"xrayConfigTorrentDesc" = "更改配置模板避免用户使用bittorrent重启面板生效"
"xrayConfigPrivateIp" = "禁止私人 ip 范围连接"
"xrayConfigPrivateIpDesc" = "更改配置模板以避免连接私有 IP 范围,重启面板生效"
"xrayConfigInbounds" = "入站配置"
"xrayConfigInboundsDesc" = "更改配置模板接受特殊客户端,重启面板生效"
"xrayConfigOutbounds" = "出站配置"
"xrayConfigOutboundsDesc" = "更改配置模板定义此服务器的传出方式,重启面板生效"
"xrayConfigRoutings" = "路由规则配置"
"xrayConfigRoutingsDesc" = "更改配置模板为该服务器定义路由规则,重启面板生效"
"telegramBotEnable" = "启用电报机器人" "telegramBotEnable" = "启用电报机器人"
"telegramBotEnableDesc" = "重启面板生效" "telegramBotEnableDesc" = "重启面板生效"
"telegramToken" = "电报机器人TOKEN" "telegramToken" = "电报机器人TOKEN"
@@ -189,5 +201,4 @@
"getSetting" = "获取设置" "getSetting" = "获取设置"
"modifyUser" = "修改用户" "modifyUser" = "修改用户"
"originalUserPassIncorrect" = "原用户名或原密码错误" "originalUserPassIncorrect" = "原用户名或原密码错误"
"userPassMustBeNotEmpty" = "新用户名和新密码不能为空" "userPassMustBeNotEmpty" = "新用户名和新密码不能为空"