mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-14 21:32:30 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1700e85d06 | ||
|
|
931e949442 | ||
|
|
8bca416142 | ||
|
|
adf2b96f38 | ||
|
|
e47ea983bd | ||
|
|
b62f747e88 | ||
|
|
784e6e24e2 | ||
|
|
4af4aadd14 | ||
|
|
9b3415865a | ||
|
|
8b6ea9e0d5 | ||
|
|
2a6f678b53 | ||
|
|
7225f00c2b | ||
|
|
85db586d95 | ||
|
|
2d7663f971 | ||
|
|
c935014ba9 | ||
|
|
2c61b5a426 | ||
|
|
a5cfe4fc1e | ||
|
|
3cc3b3b04d | ||
|
|
8e550bc308 |
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
66
.github/workflows/docker.yml
vendored
66
.github/workflows/docker.yml
vendored
@@ -1,18 +1,12 @@
|
||||
name: Docker Image CI
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
project:
|
||||
description: 'Project'
|
||||
required: true
|
||||
default: ''
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -20,30 +14,42 @@ jobs:
|
||||
with:
|
||||
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
|
||||
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
|
||||
id: buildx
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
with:
|
||||
buildx-version: latest
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build Dockerfile
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
DOCKERHUB_REPO: ${{ secrets.DOCKER_HUB_REPOSITORY }}
|
||||
run: |
|
||||
docker buildx build \
|
||||
--platform=linux/amd64,linux/arm64 \
|
||||
--output "type=image,push=true" \
|
||||
--file ./Dockerfile ./ \
|
||||
--tag $(echo "${DOCKERHUB_USERNAME}" | tr '[:upper:]' '[:lower:]')/${{ github.event.inputs.project }}:latest
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
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 }}
|
||||
|
||||
17
.github/workflows/release.yml
vendored
17
.github/workflows/release.yml
vendored
@@ -4,9 +4,10 @@ on:
|
||||
tags:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-18.04
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
steps:
|
||||
@@ -14,7 +15,7 @@ jobs:
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
@@ -23,7 +24,7 @@ jobs:
|
||||
linuxamd64build:
|
||||
name: build x-ui amd64 version
|
||||
needs: release
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Go
|
||||
@@ -54,7 +55,7 @@ jobs:
|
||||
- name: upload
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.release.outputs.upload_url }}
|
||||
asset_path: x-ui-linux-amd64.tar.gz
|
||||
@@ -63,7 +64,7 @@ jobs:
|
||||
linuxarm64build:
|
||||
name: build x-ui arm64 version
|
||||
needs: release
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Go
|
||||
@@ -96,7 +97,7 @@ jobs:
|
||||
- name: upload
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.release.outputs.upload_url }}
|
||||
asset_path: x-ui-linux-arm64.tar.gz
|
||||
@@ -105,7 +106,7 @@ jobs:
|
||||
linuxs390xbuild:
|
||||
name: build x-ui s390x version
|
||||
needs: release
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Go
|
||||
@@ -138,7 +139,7 @@ jobs:
|
||||
- name: upload
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GAYHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.release.outputs.upload_url }}
|
||||
asset_path: x-ui-linux-s390x.tar.gz
|
||||
|
||||
@@ -7,10 +7,10 @@ RUN go build main.go
|
||||
|
||||
FROM alpine
|
||||
LABEL org.opencontainers.image.authors="alireza7@gmail.com"
|
||||
RUN apk add ca-certificates tzdata
|
||||
ENV TZ=Asia/Tehran
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add ca-certificates tzdata && mkdir bin
|
||||
COPY --from=builder /app/main /app/x-ui
|
||||
COPY ./bin/. /app/bin/.
|
||||
VOLUME [ "/etc/x-ui" ]
|
||||
CMD [ "./x-ui" ]
|
||||
@@ -1,4 +1,9 @@
|
||||
# x-ui
|
||||

|
||||

|
||||
[](https://goreportcard.com/report/github.com/alireza0/x-ui)
|
||||
[](https://img.shields.io/github/downloads/alireza0/x-ui/total.svg)
|
||||
[](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**
|
||||
|
||||
|
||||
@@ -28,7 +33,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
|
||||
- Support one-click SSL certificate application and automatic renewal
|
||||
- For more advanced configuration items, please refer to the panel
|
||||
|
||||
# Inbouds picture
|
||||
# Screenshoot from Inbouds page
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.2.0
|
||||
0.2.3
|
||||
|
||||
@@ -171,7 +171,7 @@ class AllSetting {
|
||||
this.tgRunTime = "";
|
||||
this.xrayTemplateConfig = "";
|
||||
|
||||
this.timeLocation = "Asia/Shanghai";
|
||||
this.timeLocation = "Asia/Tehran";
|
||||
|
||||
if (data == null) {
|
||||
return
|
||||
|
||||
@@ -952,8 +952,7 @@ class Inbound extends XrayCommonClass {
|
||||
address = this.stream.tls.server;
|
||||
}
|
||||
}
|
||||
|
||||
remark = this.settings.vmesses[clientIndex].email ?? remark;
|
||||
|
||||
let obj = {
|
||||
v: '2',
|
||||
ps: remark,
|
||||
@@ -976,7 +975,6 @@ class Inbound extends XrayCommonClass {
|
||||
const port = this.port;
|
||||
const type = this.stream.network;
|
||||
const params = new Map();
|
||||
remark = settings.vlesses[clientIndex].email ?? remark;
|
||||
params.set("type", this.stream.network);
|
||||
if (this.xtls) {
|
||||
params.set("security", "xtls");
|
||||
@@ -1061,16 +1059,27 @@ class Inbound extends XrayCommonClass {
|
||||
|
||||
genTrojanLink(address='', remark='', clientIndex=0) {
|
||||
let settings = this.settings;
|
||||
remark = settings.trojans[clientIndex].email ?? remark;
|
||||
return `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
|
||||
}
|
||||
|
||||
genLink(address='', remark='', clientIndex=0) {
|
||||
switch (this.protocol) {
|
||||
case Protocols.VMESS: return this.genVmessLink(address, remark, clientIndex);
|
||||
case Protocols.VLESS: return this.genVLESSLink(address, remark, clientIndex);
|
||||
case Protocols.VMESS:
|
||||
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.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 '';
|
||||
}
|
||||
}
|
||||
@@ -1188,7 +1197,7 @@ Inbound.VmessSettings = class extends Inbound.Settings {
|
||||
}
|
||||
};
|
||||
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();
|
||||
this.id = id;
|
||||
this.alterId = alterId;
|
||||
@@ -1270,7 +1279,7 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
|
||||
};
|
||||
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();
|
||||
this.id = id;
|
||||
this.flow = flow;
|
||||
@@ -1384,7 +1393,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
|
||||
}
|
||||
};
|
||||
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();
|
||||
this.password = password;
|
||||
this.flow = flow;
|
||||
|
||||
@@ -136,6 +136,16 @@ class RandomUtil {
|
||||
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 {
|
||||
|
||||
@@ -6,26 +6,26 @@
|
||||
<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 @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>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template slot="client" slot-scope="text, client">
|
||||
[[ 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 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 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>
|
||||
<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 color="blue">[[ sizeFormat(getUpStats(record, client.email)) ]] / [[ sizeFormat(getDownStats(record, client.email)) ]]</a-tag>
|
||||
<template v-if="client._totalGB > 0">
|
||||
<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 slot="expiryTime" slot-scope="text, client, index">
|
||||
<template v-if="client._expiryTime > 0">
|
||||
<a-tag v-if="isExpiry(record, index)" color="red">
|
||||
[[ DateUtil.formatMillis(client._expiryTime) ]]
|
||||
</a-tag>
|
||||
<a-tag v-else color="blue">
|
||||
<a-tag :color="isExpiry(record, index)? 'red' : 'blue'">
|
||||
[[ DateUtil.formatMillis(client._expiryTime) ]]
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{{define "inboundInfoModal"}}
|
||||
<a-modal id="inbound-info-modal" v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}'
|
||||
:closable="true"
|
||||
:mask-closable="true"
|
||||
:footer="null"
|
||||
>
|
||||
<a-modal id="inbound-info-modal"
|
||||
v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}'
|
||||
:closable="true"
|
||||
:mask-closable="true"
|
||||
:footer="null"
|
||||
width="600px"
|
||||
>
|
||||
<table style="margin-bottom: 10px; width: 100%;">
|
||||
<tr><td>
|
||||
<table>
|
||||
@@ -55,11 +57,47 @@
|
||||
</tr>
|
||||
</table>
|
||||
<a-divider>{{ i18n "pages.inbounds.client" }}</a-divider>
|
||||
<template v-if="dbInbound.hasLink()">
|
||||
<p>Client URL:</p>
|
||||
<table style="margin-bottom: 10px; width: 100%;">
|
||||
<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>
|
||||
<button class="btn" id="copy-url-link"><a-icon type="snippets"></a-icon>{{ i18n "copy" }}</button>
|
||||
</template>
|
||||
<button class="ant-btn ant-btn-primary" id="copy-url-link"><a-icon type="snippets"></a-icon>{{ i18n "copy" }}</button>
|
||||
</div>
|
||||
</a-modal>
|
||||
<script>
|
||||
|
||||
@@ -67,14 +105,32 @@
|
||||
visible: false,
|
||||
inbound: new Inbound(),
|
||||
dbInbound: new DBInbound(),
|
||||
clientSettings: new Inbound.Settings(),
|
||||
clientStats: [],
|
||||
upStats: 0,
|
||||
downStats: 0,
|
||||
clipboard: null,
|
||||
link: null,
|
||||
index: 0,
|
||||
isExpired: false,
|
||||
show(dbInbound, index=0) {
|
||||
this.index = index;
|
||||
this.inbound = dbInbound.toInbound();
|
||||
this.dbInbound = new DBInbound(dbInbound);
|
||||
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;
|
||||
infoModalApp.$nextTick(() => {
|
||||
if (this.clipboard === null) {
|
||||
@@ -120,6 +176,11 @@
|
||||
app.$message.success('{{ i18n "copied" }}')
|
||||
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'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -196,18 +196,18 @@
|
||||
}];
|
||||
|
||||
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.traffic" }}', width: 100, scopedSlots: { customRender: 'traffic' } },
|
||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 80, scopedSlots: { customRender: 'expiryTime' } },
|
||||
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 80, scopedSlots: { customRender: 'traffic' } },
|
||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
|
||||
{ title: 'UID', width: 150, dataIndex: "id" },
|
||||
];
|
||||
|
||||
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.traffic" }}', width: 100, scopedSlots: { customRender: 'traffic' } },
|
||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 80, scopedSlots: { customRender: 'expiryTime' } },
|
||||
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 80, scopedSlots: { customRender: 'traffic' } },
|
||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
|
||||
{ title: 'Password', width: 150, dataIndex: "password" },
|
||||
];
|
||||
|
||||
@@ -257,7 +257,18 @@
|
||||
this.searchedInbounds.splice(0, this.searchedInbounds.length);
|
||||
this.dbInbounds.forEach(inbound => {
|
||||
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: {
|
||||
|
||||
@@ -87,13 +87,28 @@
|
||||
style="max-width: 300px"></a-input>
|
||||
</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-form-item>
|
||||
</a-form>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="3" tab='{{ i18n "pages.setting.xrayConfiguration"}}'>
|
||||
<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>
|
||||
</a-list>
|
||||
</a-tab-pane>
|
||||
@@ -189,6 +204,102 @@
|
||||
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>
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
"username" = "username"
|
||||
"password" = "password"
|
||||
"login" = "login"
|
||||
"confirm" = "confirm"
|
||||
"cancel" = "cancel"
|
||||
"close" = "close"
|
||||
"copy" = "copy"
|
||||
"copied" = "copied"
|
||||
"download" = "download"
|
||||
"remark" = "remark"
|
||||
"enable" = "enable"
|
||||
"protocol" = "protocol"
|
||||
"search" = "search"
|
||||
"username" = "Username"
|
||||
"password" = "Password"
|
||||
"login" = "Login"
|
||||
"confirm" = "Confirm"
|
||||
"cancel" = "Cancel"
|
||||
"close" = "Close"
|
||||
"copy" = "Copy"
|
||||
"copied" = "Copied"
|
||||
"download" = "Download"
|
||||
"remark" = "Remark"
|
||||
"enable" = "Enable"
|
||||
"protocol" = "Protocol"
|
||||
"search" = "Search"
|
||||
|
||||
"loading" = "Loading"
|
||||
"second" = "second"
|
||||
"minute" = "minute"
|
||||
"hour" = "hour"
|
||||
"day" = "day"
|
||||
"check" = "check"
|
||||
"indefinite" = "indefinite"
|
||||
"unlimited" = "unlimited"
|
||||
"none" = "none"
|
||||
"second" = "Second"
|
||||
"minute" = "Minute"
|
||||
"hour" = "Hour"
|
||||
"day" = "Day"
|
||||
"check" = "Check"
|
||||
"indefinite" = "Indefinite"
|
||||
"unlimited" = "Unlimited"
|
||||
"none" = "None"
|
||||
"qrCode" = "QR Code"
|
||||
"info" = "More information"
|
||||
"edit" = "edit"
|
||||
"delete" = "delete"
|
||||
"reset" = "reset"
|
||||
"edit" = "Edit"
|
||||
"delete" = "Delete"
|
||||
"reset" = "Reset"
|
||||
"copySuccess" = "Copy successfully"
|
||||
"sure" = "Sure"
|
||||
"encryption" = "encryption"
|
||||
"transmission" = "transmission"
|
||||
"host" = "host"
|
||||
"path" = "path"
|
||||
"camouflage" = "camouflage"
|
||||
"enabled" = "enabled"
|
||||
"disabled" = "disabled"
|
||||
"domainName" = "domain name"
|
||||
"additional" = "alter"
|
||||
"encryption" = "Encryption"
|
||||
"transmission" = "Transmission"
|
||||
"host" = "Host"
|
||||
"path" = "Path"
|
||||
"camouflage" = "Camouflage"
|
||||
"enabled" = "Enabled"
|
||||
"disabled" = "Disabled"
|
||||
"domainName" = "Domain name"
|
||||
"additional" = "Alter"
|
||||
"monitor" = "Listen IP"
|
||||
"certificate" = "certificat"
|
||||
"fail" = "fail"
|
||||
"success" = " success"
|
||||
"getVersion" = "get version"
|
||||
"install" = "install"
|
||||
"certificate" = "Certificat"
|
||||
"fail" = "Fail"
|
||||
"success" = " Success"
|
||||
"getVersion" = "Get version"
|
||||
"install" = "Install"
|
||||
"clients" = "Clients"
|
||||
"usage" = "Usage"
|
||||
|
||||
@@ -64,11 +64,10 @@
|
||||
"wrongUsernameOrPassword" = "Invalid username or password"
|
||||
"successLogin" = "Login"
|
||||
|
||||
|
||||
[pages.index]
|
||||
"title" = "system status"
|
||||
"memory" = "memory"
|
||||
"hard" = "hard disk"
|
||||
"title" = "System status"
|
||||
"memory" = "Memory"
|
||||
"hard" = "Hard disk"
|
||||
"xrayStatus" = "xray Status"
|
||||
"xraySwitch" = "Switch Version"
|
||||
"xraySwitchClick" = "Click on the version you want to switch"
|
||||
@@ -82,27 +81,26 @@
|
||||
"downSpeed" = "Total download speed for all network cards"
|
||||
"totalSent" = "Total upload traffic of all network cards since system startup"
|
||||
"totalReceive" = "Total download traffic of all network cards since system startup"
|
||||
"xraySwitchVersionDialog" = "switch xray version"
|
||||
"xraySwitchVersionDialogDesc" = "whether to switch the xray version to"
|
||||
"xraySwitchVersionDialog" = "Switch xray version"
|
||||
"xraySwitchVersionDialogDesc" = "Whether to switch the xray version to"
|
||||
"dontRefreshh" = "Installation is in progress, please do not refresh this page"
|
||||
|
||||
|
||||
[pages.inbounds]
|
||||
"title" = "Inbounds"
|
||||
"totalDownUp" = "Total uploads/downloads"
|
||||
"totalUsage" = "Total usage"
|
||||
"inboundCount" = "Number of inbound"
|
||||
"operate" = "operate"
|
||||
"enable" = "enable"
|
||||
"remark" = "remark"
|
||||
"protocol" = "protocol"
|
||||
"port" = "port"
|
||||
"traffic" = "traffic"
|
||||
"details" = "details"
|
||||
"transportConfig" = "transport config"
|
||||
"expireDate" = "expire date"
|
||||
"resetTraffic" = "reset traffic"
|
||||
"addInbound" = "addInbound"
|
||||
"operate" = "Operate"
|
||||
"enable" = "Enable"
|
||||
"remark" = "Remark"
|
||||
"protocol" = "Protocol"
|
||||
"port" = "Port"
|
||||
"traffic" = "Traffic"
|
||||
"details" = "Details"
|
||||
"transportConfig" = "Transport config"
|
||||
"expireDate" = "Expire date"
|
||||
"resetTraffic" = "Reset traffic"
|
||||
"addInbound" = "Add Inbound"
|
||||
"addTo" = "Add To"
|
||||
"revise" = "Revise"
|
||||
"modifyInbound" = "Modify InBound"
|
||||
@@ -110,45 +108,44 @@
|
||||
"deleteInboundContent" = "Are you sure you want to delete inbound?"
|
||||
"resetTrafficContent" = "Are you sure you want to reset traffic?"
|
||||
"copyLink" = "Copy Link"
|
||||
"address" = "address"
|
||||
"network" = "network"
|
||||
"destinationPort" = "destination port"
|
||||
"targetAddress" = "target address"
|
||||
"address" = "Address"
|
||||
"network" = "Network"
|
||||
"destinationPort" = "Destination port"
|
||||
"targetAddress" = "Target address"
|
||||
"disableInsecureEncryption" = "Disable insecure encryption"
|
||||
"monitorDesc" = "Leave blank by default"
|
||||
"meansNoLimit" = "means no limit"
|
||||
"totalFlow" = "total flow"
|
||||
"meansNoLimit" = "Means no limit"
|
||||
"totalFlow" = "Total flow"
|
||||
"leaveBlankToNeverExpire" = "Leave blank to never expire"
|
||||
"noRecommendKeepDefault" = "There are no special requirements to keep the default"
|
||||
"certificatePath" = "certificate file path"
|
||||
"certificateContent" = "certificate file content"
|
||||
"publicKeyPath" = "public key file path"
|
||||
"publicKeyContent" = "public key content"
|
||||
"keyPath" = "key file path"
|
||||
"keyContent" = "key content"
|
||||
"clickOnQRcode" = "click on QR Code to Copy"
|
||||
"certificatePath" = "Certificate file path"
|
||||
"certificateContent" = "Certificate file content"
|
||||
"publicKeyPath" = "Public key file path"
|
||||
"publicKeyContent" = "Public key content"
|
||||
"keyPath" = "Key file path"
|
||||
"keyContent" = "Key content"
|
||||
"clickOnQRcode" = "Click on QR Code to Copy"
|
||||
"client" = "Client"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "Obtain"
|
||||
|
||||
[pages.inbounds.stream.general]
|
||||
"requestHeader" = "request header"
|
||||
"name" = "name"
|
||||
"value" = "value"
|
||||
"requestHeader" = "Request header"
|
||||
"name" = "Name"
|
||||
"value" = "Value"
|
||||
|
||||
[pages.inbounds.stream.tcp]
|
||||
"requestVersion" = "request version"
|
||||
"requestMethod" = "request method"
|
||||
"requestPath" = "request path"
|
||||
"responseVersion" = "response version"
|
||||
"responseStatus" = "response status"
|
||||
"responseStatusDescription" = "response status description"
|
||||
"responseHeader" = "response header"
|
||||
"requestVersion" = "Request version"
|
||||
"requestMethod" = "Request method"
|
||||
"requestPath" = "Request path"
|
||||
"responseVersion" = "Response version"
|
||||
"responseStatus" = "Response status"
|
||||
"responseStatusDescription" = "Response status description"
|
||||
"responseHeader" = "Response header"
|
||||
|
||||
[pages.inbounds.stream.quic]
|
||||
"encryption" = "encryption"
|
||||
|
||||
"encryption" = "Encryption"
|
||||
|
||||
[pages.setting]
|
||||
"title" = "Setting"
|
||||
@@ -174,8 +171,20 @@
|
||||
"currentPassword" = "Current Password"
|
||||
"newUsername" = "New Username"
|
||||
"newPassword" = "New Password"
|
||||
"xrayConfigTemplate" = "xray Configuration Template"
|
||||
"xrayConfigTemplateDesc" = "Generate the final xray configuration file based on this template, restart the panel to take effect"
|
||||
"advancedTemplate" = "Advanced template parts"
|
||||
"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"
|
||||
"telegramBotEnableDesc" = "Restart the panel to take effect"
|
||||
"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"
|
||||
|
||||
[pages.setting.toasts]
|
||||
"modifySetting" = "modify setting"
|
||||
"getSetting" = "get setting"
|
||||
"modifyUser" = "modify user"
|
||||
"modifySetting" = "Modify setting"
|
||||
"getSetting" = "Get setting"
|
||||
"modifyUser" = "Modify user"
|
||||
"originalUserPassIncorrect" = "The original user name or original password is incorrect"
|
||||
"userPassMustBeNotEmpty" = "New username and new password cannot be empty"
|
||||
@@ -34,7 +34,7 @@
|
||||
"path" = "مسیر"
|
||||
"camouflage" = "استتار"
|
||||
"enabled" = "فعال"
|
||||
"disabled" = "disabled"
|
||||
"disabled" = "غیرفعال"
|
||||
"domainName" = "آدرس دامنه"
|
||||
"additional" = "آی دی جایگزین"
|
||||
"monitor" = "آی پی اتصال"
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
[menu]
|
||||
"dashboard" = "وضعیت سیستم"
|
||||
"inbounds" = "سروریس ها"
|
||||
"inbounds" = "سرویس ها"
|
||||
"setting" = "تنظیمات پنل"
|
||||
"logout" = "خروج"
|
||||
"link" = "دیگر"
|
||||
@@ -64,7 +64,6 @@
|
||||
"wrongUsernameOrPassword" = "نام کاربری و رمز عبور اشتباه میباشد"
|
||||
"successLogin" = "خوش آمدید"
|
||||
|
||||
|
||||
[pages.index]
|
||||
"title" = "وضعیت سیستم"
|
||||
"memory" = "حافظه رم"
|
||||
@@ -86,7 +85,6 @@
|
||||
"xraySwitchVersionDialogDesc" = "آیا از تغییر ورژن مطمئن هستین"
|
||||
"dontRefreshh" = "در حال نصب ، لطفا رفرش نکنید "
|
||||
|
||||
|
||||
[pages.inbounds]
|
||||
"title" = "کاربران"
|
||||
"totalDownUp" = "جمع آپلود/دانلود"
|
||||
@@ -149,7 +147,6 @@
|
||||
[pages.inbounds.stream.quic]
|
||||
"encryption" = "رمزنگاری"
|
||||
|
||||
|
||||
[pages.setting]
|
||||
"title" = "تنظیمات"
|
||||
"save" = "ذخیره"
|
||||
@@ -174,8 +171,20 @@
|
||||
"currentPassword" = "رمز عبور فعلی"
|
||||
"newUsername" = "نام کاربری جدید"
|
||||
"newPassword" = "رمز عبور جدید"
|
||||
"xrayConfigTemplate" = "تنظیمات قالب Xray"
|
||||
"xrayConfigTemplateDesc" = "فایل پیکربندی xray نهایی را بر اساس این الگو ایجاد کنید. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید! پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"advancedTemplate" = "بخش های پیشرفته الگو"
|
||||
"completeTemplate" = "الگوی کامل تنظیمات ایکس ری"
|
||||
"xrayConfigTemplate" = "تنظیمات الگو ایکس ری"
|
||||
"xrayConfigTemplateDesc" = "فایل پیکربندی ایکس ری نهایی بر اساس این الگو ایجاد میشود. لطفاً این را تغییر ندهید مگر اینکه دقیقاً بدانید که چه کاری انجام می دهید! پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"xrayConfigTorrent" = "فیلتر کردن بیت تورنت"
|
||||
"xrayConfigTorrentDesc" = "الگوی تنظیمات را برای فیلتر کردن پروتکل بیت تورنت برای کاربران تغییر میدهد. پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"xrayConfigPrivateIp" = "جلوگیری از اتصال آی پی های نامعتبر"
|
||||
"xrayConfigPrivateIpDesc" = "الگوی تنظیمات را برای فیلتر کردن اتصال آی پی های نامعتبر و بسته های سرگردان تغییر میدهد. پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"xrayConfigInbounds" = "تنظیمات ورودی"
|
||||
"xrayConfigInboundsDesc" = "میتوانید الگوی تنظیمات را برای ورودی های خاص تنظیم نمایید. پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"xrayConfigOutbounds" = "تنظیمات خروجی"
|
||||
"xrayConfigOutboundsDesc" = "میتوانید الگوی تنظیمات را برای خروجی اینترنت تنظیم نمایید. پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"xrayConfigRoutings" = "تنظیمات قوانین مسیریابی"
|
||||
"xrayConfigRoutingsDesc" = "میتوانید الگوی تنظیمات را برای مسیریابی تنظیم نمایید. پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"telegramBotEnable" = "فعالسازی ربات تلگرام"
|
||||
"telegramBotEnableDesc" = "پنل را مجدداً راه اندازی کنید تا اعمال شود"
|
||||
"telegramToken" = "توکن تلگرام"
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"getVersion" = "获取版本"
|
||||
"install" = "安装"
|
||||
"clients" = "客户端"
|
||||
"usage" = "用法"
|
||||
|
||||
[menu]
|
||||
"dashboard" = "系统状态"
|
||||
@@ -84,7 +85,6 @@
|
||||
"xraySwitchVersionDialogDesc" = "是否切换 xray 版本至"
|
||||
"dontRefreshh" = "安装中,请不要刷新此页面"
|
||||
|
||||
|
||||
[pages.inbounds]
|
||||
"title" = "入站列表"
|
||||
"totalDownUp" = "总上传 / 下载"
|
||||
@@ -124,7 +124,8 @@
|
||||
"publicKeyContent" = "公钥内容"
|
||||
"keyPath" = "密钥文件路径"
|
||||
"keyContent" = "密钥内容"
|
||||
"clickOnQRcode" = "click on QR Code to Copy"
|
||||
"clickOnQRcode" = "点击二维码复制"
|
||||
"client" = "客户"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "获取"
|
||||
@@ -146,7 +147,6 @@
|
||||
[pages.inbounds.stream.quic]
|
||||
"encryption" = "加密"
|
||||
|
||||
|
||||
[pages.setting]
|
||||
"title" = "设置"
|
||||
"save" = "保存配置"
|
||||
@@ -171,8 +171,20 @@
|
||||
"currentPassword" = "原密码"
|
||||
"newUsername" = "新用户名"
|
||||
"newPassword" = "新密码"
|
||||
"xrayConfigTemplate" = "xray 配置模版"
|
||||
"xrayConfigTemplateDesc" = "以该模版为基础生成最终的 xray 配置文件,重启面板生效"
|
||||
"advancedTemplate" = "高级模板部件"
|
||||
"completeTemplate" = "Xray 配置的完整模板"
|
||||
"xrayConfigTemplate" = "xray 配置模板"
|
||||
"xrayConfigTemplateDesc" = "以该模型为基础生成最终的xray配置文件,重新启动面板生成效率"
|
||||
"xrayConfigTorrent" = "禁止使用 bittorrent"
|
||||
"xrayConfigTorrentDesc" = "更改配置模板避免用户使用bittorrent,重启面板生效"
|
||||
"xrayConfigPrivateIp" = "禁止私人 ip 范围连接"
|
||||
"xrayConfigPrivateIpDesc" = "更改配置模板以避免连接私有 IP 范围,重启面板生效"
|
||||
"xrayConfigInbounds" = "入站配置"
|
||||
"xrayConfigInboundsDesc" = "更改配置模板接受特殊客户端,重启面板生效"
|
||||
"xrayConfigOutbounds" = "出站配置"
|
||||
"xrayConfigOutboundsDesc" = "更改配置模板定义此服务器的传出方式,重启面板生效"
|
||||
"xrayConfigRoutings" = "路由规则配置"
|
||||
"xrayConfigRoutingsDesc" = "更改配置模板为该服务器定义路由规则,重启面板生效"
|
||||
"telegramBotEnable" = "启用电报机器人"
|
||||
"telegramBotEnableDesc" = "重启面板生效"
|
||||
"telegramToken" = "电报机器人TOKEN"
|
||||
@@ -189,5 +201,4 @@
|
||||
"getSetting" = "获取设置"
|
||||
"modifyUser" = "修改用户"
|
||||
"originalUserPassIncorrect" = "原用户名或原密码错误"
|
||||
"userPassMustBeNotEmpty" = "新用户名和新密码不能为空"
|
||||
|
||||
"userPassMustBeNotEmpty" = "新用户名和新密码不能为空"
|
||||
Reference in New Issue
Block a user