Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md45
-rw-r--r--docker-compose.yml15
-rw-r--r--web/controller/index.go3
-rw-r--r--web/controller/setting.go18
-rw-r--r--web/controller/xui.go2
-rw-r--r--web/html/common/qrcode_modal.html10
-rw-r--r--web/html/login.html8
-rw-r--r--web/html/xui/client_modal.html6
-rw-r--r--web/html/xui/common_sider.html8
-rw-r--r--web/html/xui/component/themeSwitch.html4
-rw-r--r--web/html/xui/form/client.html4
-rw-r--r--web/html/xui/form/protocol/shadowsocks.html4
-rw-r--r--web/html/xui/form/protocol/trojan.html4
-rw-r--r--web/html/xui/form/protocol/vless.html4
-rw-r--r--web/html/xui/form/protocol/vmess.html4
-rw-r--r--web/html/xui/inbound_info_modal.html13
-rw-r--r--web/html/xui/inbounds.html31
-rw-r--r--web/html/xui/index.html2
-rw-r--r--web/html/xui/settings.html57
-rw-r--r--web/service/server.go4
-rw-r--r--web/service/setting.go27
-rw-r--r--web/service/sub.go4
-rw-r--r--web/translation/translate.en_US.toml10
-rw-r--r--web/translation/translate.fa_IR.toml6
-rw-r--r--web/translation/translate.ru_RU.toml10
-rw-r--r--web/translation/translate.zh_Hans.toml6
-rw-r--r--web/web.go4
27 files changed, 225 insertions, 88 deletions
diff --git a/README.md b/README.md
index 9a85c3e1..92b47b37 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-# 3x-ui
+# 3x-ui
+
> **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**
[![](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases)
@@ -12,7 +13,8 @@
**If you think this project is helpful to you, you may wish to give a** :star2:
**Buy Me a Coffee :**
- - Tron USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC`
+
+- Tron USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC`
# Install & Upgrade
@@ -47,12 +49,12 @@ or you can use x-ui menu then number '16' (Apply for an SSL Certificate)
Before you set ssl on settings
-- http://ip:2053/xui
-- http://domain:2053/xui
+- http://ip:2053/panel
+- http://domain:2053/panel
After you set ssl on settings
-- https://yourdomain:2053/xui
+- https://yourdomain:2053/panel
# Environment Variables
@@ -69,6 +71,31 @@ Example:
XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
```
+# Install with Docker
+
+1. Install Docker:
+ ```sh
+ bash <(curl -sSL https://get.docker.com)
+ ```
+2. Run 3x-ui:
+
+ ```sh
+ docker compose up -d
+ ```
+
+ OR
+
+ ```sh
+ docker run -itd \
+ -e XRAY_VMESS_AEAD_FORCED=false \
+ -v $PWD/db/:/etc/x-ui/ \
+ -v $PWD/cert/:/root/cert/ \
+ --network=host \
+ --restart=unless-stopped \
+ --name 3x-ui \
+ ghcr.io/mhsanaei/3x-ui:latest
+ ```
+
# Xray Configurations:
**copy and paste to xray Configuration :** (you don't need to do this if you have a fresh install)
@@ -173,19 +200,19 @@ Reference syntax:
| `POST` | `"/clientIps/:email"` | Client Ip address |
| `POST` | `"/clearClientIps/:email"` | Clear Client Ip address |
| `POST` | `"/addClient"` | Add Client to inbound |
-| `POST` | `"/:id/delClient/:clientId"` | Delete Client by clientId* |
-| `POST` | `"/updateClient/:clientId"` | Update Client by clientId* |
+| `POST` | `"/:id/delClient/:clientId"` | Delete Client by clientId\* |
+| `POST` | `"/updateClient/:clientId"` | Update Client by clientId\* |
| `POST` | `"/:id/resetClientTraffic/:email"` | Reset Client's Traffic |
| `POST` | `"/resetAllTraffics"` | Reset traffics of all inbounds |
| `POST` | `"/resetAllClientTraffics/:id"` | Reset traffics of all clients in an inbound |
| `POST` | `"/delDepletedClients/:id"` | Delete inbound depleted clients (-1: all) |
-*- The field `clientId` should be filled by:
+\*- The field `clientId` should be filled by:
+
- `client.id` for VMESS and VLESS
- `client.password` for TROJAN
- `client.email` for Shadowsocks
-
- [Postman Collection](https://gist.github.com/mehdikhody/9a862801a2e41f6b5fb6bbc7e1326044)
# A Special Thanks To
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..f0231309
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,15 @@
+---
+version: "3.9"
+
+services:
+ 3x-ui:
+ image: ghcr.io/mhsanaei/3x-ui:latest
+ container_name: 3x-ui
+ volumes:
+ - $PWD/db/:/etc/x-ui/
+ - $PWD/cert/:/root/cert/
+ environment:
+ XRAY_VMESS_AEAD_FORCED: "false"
+ tty: true
+ network_mode: host
+ restart: unless-stopped
diff --git a/web/controller/index.go b/web/controller/index.go
index 802f3f7d..b0ee83f8 100644
--- a/web/controller/index.go
+++ b/web/controller/index.go
@@ -39,7 +39,7 @@ func (a *IndexController) initRouter(g *gin.RouterGroup) {
func (a *IndexController) index(c *gin.Context) {
if session.IsLogin(c) {
- c.Redirect(http.StatusTemporaryRedirect, "xui/")
+ c.Redirect(http.StatusTemporaryRedirect, "panel/")
return
}
html(c, "login.html", "pages.login.title", nil)
@@ -101,5 +101,4 @@ func (a *IndexController) getSecretStatus(c *gin.Context) {
if err == nil {
jsonObj(c, status, nil)
}
-
}
diff --git a/web/controller/setting.go b/web/controller/setting.go
index bd9c2a5f..248f3ee5 100644
--- a/web/controller/setting.go
+++ b/web/controller/setting.go
@@ -3,6 +3,7 @@ package controller
import (
"errors"
"time"
+ "x-ui/util/common"
"x-ui/web/entity"
"x-ui/web/service"
"x-ui/web/session"
@@ -44,6 +45,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
g.GET("/getDefaultJsonConfig", a.getDefaultJsonConfig)
g.POST("/updateUserSecret", a.updateSecret)
g.POST("/getUserSecret", a.getUserSecret)
+ g.GET("/searchDatafiles", a.searchDatafiles)
}
func (a *SettingController) getAllSetting(c *gin.Context) {
@@ -149,6 +151,7 @@ func (a *SettingController) updateSecret(c *gin.Context) {
}
jsonMsg(c, I18n(c, "pages.settings.toasts.modifyUser"), err)
}
+
func (a *SettingController) getUserSecret(c *gin.Context) {
loginUser := session.GetLoginUser(c)
user := a.userService.GetUserSecret(loginUser.Id)
@@ -156,3 +159,18 @@ func (a *SettingController) getUserSecret(c *gin.Context) {
jsonObj(c, user, nil)
}
}
+
+func (a *SettingController) searchDatafiles(c *gin.Context) {
+ searchString := c.Query("query")
+ if searchString == "" {
+ err := common.NewError("data query parameter is empty")
+ jsonMsg(c, "Invalid query:", err)
+ return
+ }
+ found, err := a.settingService.SearchDatafiles(searchString)
+ if err != nil {
+ jsonMsg(c, "Something went wrong!", err)
+ return
+ }
+ jsonObj(c, found, nil)
+}
diff --git a/web/controller/xui.go b/web/controller/xui.go
index 1844181d..700bd52c 100644
--- a/web/controller/xui.go
+++ b/web/controller/xui.go
@@ -18,7 +18,7 @@ func NewXUIController(g *gin.RouterGroup) *XUIController {
}
func (a *XUIController) initRouter(g *gin.RouterGroup) {
- g = g.Group("/xui")
+ g = g.Group("/panel")
g.Use(a.checkLogin)
g.GET("/", a.index)
diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html
index 2bd2f00f..855c349a 100644
--- a/web/html/common/qrcode_modal.html
+++ b/web/html/common/qrcode_modal.html
@@ -7,7 +7,10 @@
<a-tag color="green" style="margin-bottom: 10px;display: block;text-align: center;">
{{ i18n "pages.inbounds.clickOnQRcode" }}
</a-tag>
- <canvas @click="copyToClipboard()" id="qrCode" style="width: 100%; height: 100%;"></canvas>
+ <a-tag v-if="qrModal.clientName" color="orange" style="margin-bottom: 10px;display: block;text-align: center;">
+ {{ i18n "pages.inbounds.email" }}: "[[ qrModal.clientName ]]"
+ </a-tag>
+ <canvas @click="copyToClipboard()" id="qrCode" style="width: 100%; height: 100%; margin-top: 10px;"></canvas>
</a-modal>
<script>
@@ -18,14 +21,16 @@
inbound: new Inbound(),
dbInbound: new DBInbound(),
copyText: '',
+ clientName: null,
qrcode: null,
clipboard: null,
visible: false,
- show: function (title = '', content = '', dbInbound = new DBInbound(), copyText = '') {
+ show: function (title = '', content = '', dbInbound = new DBInbound(), copyText = '', clientName = null) {
this.title = title;
this.content = content;
this.dbInbound = dbInbound;
this.inbound = dbInbound.toInbound();
+ this.clientName = clientName;
if (ObjectUtil.isEmpty(copyText)) {
this.copyText = content;
} else {
@@ -50,6 +55,7 @@
};
const qrModalApp = new Vue({
+ delimiters: ['[[', ']]'],
el: '#qrcode-modal',
data: {
qrModal: qrModal,
diff --git a/web/html/login.html b/web/html/login.html
index 1b6478de..a2bde74f 100644
--- a/web/html/login.html
+++ b/web/html/login.html
@@ -46,7 +46,7 @@
</style>
<body>
-<a-layout id="app" v-cloak :class="themeSwitcher.darkClass">
+<a-layout id="app" v-cloak :class="themeSwitcher.darkCardClass">
<transition name="list" appear>
<a-layout-content>
<a-row type="flex" justify="center">
@@ -120,10 +120,10 @@
secretEnable: false,
lang: ""
},
- created() {
+ async created() {
this.updateBackground();
this.lang = getLang();
- this.secretEnable = this.getSecretStatus();
+ this.secretEnable = await this.getSecretStatus();
},
methods: {
async login() {
@@ -131,7 +131,7 @@
const msg = await HttpUtil.post('/login', this.user);
this.loading = false;
if (msg.success) {
- location.href = basePath + 'xui/';
+ location.href = basePath + 'panel/';
}
},
async getSecretStatus() {
diff --git a/web/html/xui/client_modal.html b/web/html/xui/client_modal.html
index 89175f31..f7faf888 100644
--- a/web/html/xui/client_modal.html
+++ b/web/html/xui/client_modal.html
@@ -135,7 +135,7 @@
client.email = string;
},
async getDBClientIps(email, event) {
- const msg = await HttpUtil.post('/xui/inbound/clientIps/' + email);
+ const msg = await HttpUtil.post('/panel/inbound/clientIps/' + email);
if (!msg.success) {
return;
}
@@ -149,7 +149,7 @@
}
},
async clearDBClientIps(email) {
- const msg = await HttpUtil.post('/xui/inbound/clearClientIps/' + email);
+ const msg = await HttpUtil.post('/panel/inbound/clearClientIps/' + email);
if (!msg.success) {
return;
}
@@ -164,7 +164,7 @@
cancelText: '{{ i18n "cancel"}}',
onOk: async () => {
iconElement.disabled = true;
- const msg = await HttpUtil.postWithModal('/xui/inbound/' + dbInboundId + '/resetClientTraffic/' + email);
+ const msg = await HttpUtil.postWithModal('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + email);
if (msg.success) {
this.clientModal.clientStats.up = 0;
this.clientModal.clientStats.down = 0;
diff --git a/web/html/xui/common_sider.html b/web/html/xui/common_sider.html
index 94a2e4a3..58072f82 100644
--- a/web/html/xui/common_sider.html
+++ b/web/html/xui/common_sider.html
@@ -1,17 +1,17 @@
{{define "menuItems"}}
-<a-menu-item key="{{ .base_path }}xui/">
+<a-menu-item key="{{ .base_path }}panel/">
<a-icon type="dashboard"></a-icon>
<span>{{ i18n "menu.dashboard"}}</span>
</a-menu-item>
-<a-menu-item key="{{ .base_path }}xui/inbounds">
+<a-menu-item key="{{ .base_path }}panel/inbounds">
<a-icon type="user"></a-icon>
<span>{{ i18n "menu.inbounds"}}</span>
</a-menu-item>
-<a-menu-item key="{{ .base_path }}xui/settings">
+<a-menu-item key="{{ .base_path }}panel/settings">
<a-icon type="setting"></a-icon>
<span>{{ i18n "menu.settings"}}</span>
</a-menu-item>
-<!--<a-menu-item key="{{ .base_path }}xui/clients">-->
+<!--<a-menu-item key="{{ .base_path }}panel/clients">-->
<!-- <a-icon type="laptop"></a-icon>-->
<!-- <span>Client</span>-->
<!--</a-menu-item>-->
diff --git a/web/html/xui/component/themeSwitch.html b/web/html/xui/component/themeSwitch.html
index 35013a9e..7cbedecf 100644
--- a/web/html/xui/component/themeSwitch.html
+++ b/web/html/xui/component/themeSwitch.html
@@ -28,7 +28,7 @@
isDarkTheme,
bgStyle: `background: ${colors[theme].bg};`,
textStyle: `color: ${colors[theme].text};`,
- darkClass: isDarkTheme ? 'ant-card-dark' : '',
+ darkClass: isDarkTheme ? 'ant-dark' : '',
darkCardClass: isDarkTheme ? 'ant-card-dark' : '',
darkDrawerClass: isDarkTheme ? 'ant-drawer-dark' : '',
get currentTheme() {
@@ -40,7 +40,7 @@
localStorage.setItem('dark-mode', this.isDarkTheme);
this.bgStyle = `background: ${colors[this.theme].bg};`;
this.textStyle = `color: ${colors[this.theme].text};`;
- this.darkClass = this.isDarkTheme ? 'ant-card-dark' : '';
+ this.darkClass = this.isDarkTheme ? 'ant-dark' : '';
this.darkCardClass = this.isDarkTheme ? 'ant-card-dark' : '';
this.darkDrawerClass = this.isDarkTheme ? 'ant-drawer-dark' : '';
},
diff --git a/web/html/xui/form/client.html b/web/html/xui/form/client.html
index c8ab09cf..1aaf9073 100644
--- a/web/html/xui/form/client.html
+++ b/web/html/xui/form/client.html
@@ -11,10 +11,10 @@
<br>
<a-form-item>
<span slot="label">
- <span>{{ i18n "pages.inbounds.Email" }}</span>
+ <span>{{ i18n "pages.inbounds.email" }}</span>
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.EmailDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.emailDesc" }}</span>
</template>
<a-icon type="sync" @click="getNewEmail(client)"></a-icon>
</a-tooltip>
diff --git a/web/html/xui/form/protocol/shadowsocks.html b/web/html/xui/form/protocol/shadowsocks.html
index f37c1a90..b59b4722 100644
--- a/web/html/xui/form/protocol/shadowsocks.html
+++ b/web/html/xui/form/protocol/shadowsocks.html
@@ -4,10 +4,10 @@
<a-collapse-panel header='{{ i18n "pages.inbounds.client" }}'>
<a-form-item>
<span slot="label">
- <span>{{ i18n "pages.inbounds.Email" }}</span>
+ <span>{{ i18n "pages.inbounds.email" }}</span>
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.EmailDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.emailDesc" }}</span>
</template>
<a-icon @click="getNewEmail(client)" type="sync"></a-icon>
</a-tooltip>
diff --git a/web/html/xui/form/protocol/trojan.html b/web/html/xui/form/protocol/trojan.html
index 4a2518a7..2b6a2a3b 100644
--- a/web/html/xui/form/protocol/trojan.html
+++ b/web/html/xui/form/protocol/trojan.html
@@ -4,10 +4,10 @@
<a-collapse-panel header='{{ i18n "pages.inbounds.client" }}'>
<a-form-item>
<span slot="label">
- <span>{{ i18n "pages.inbounds.Email" }}</span>
+ <span>{{ i18n "pages.inbounds.email" }}</span>
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.EmailDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.emailDesc" }}</span>
</template>
<a-icon type="sync" @click="getNewEmail(client)"></a-icon>
</a-tooltip>
diff --git a/web/html/xui/form/protocol/vless.html b/web/html/xui/form/protocol/vless.html
index 12b15711..b253a4a3 100644
--- a/web/html/xui/form/protocol/vless.html
+++ b/web/html/xui/form/protocol/vless.html
@@ -4,10 +4,10 @@
<a-collapse-panel header='{{ i18n "pages.inbounds.client" }}'>
<a-form-item>
<span slot="label">
- <span>{{ i18n "pages.inbounds.Email" }}</span>
+ <span>{{ i18n "pages.inbounds.email" }}</span>
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.EmailDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.emailDesc" }}</span>
</template>
<a-icon type="sync" @click="getNewEmail(client)"></a-icon>
</a-tooltip>
diff --git a/web/html/xui/form/protocol/vmess.html b/web/html/xui/form/protocol/vmess.html
index 2b02bd14..f703210b 100644
--- a/web/html/xui/form/protocol/vmess.html
+++ b/web/html/xui/form/protocol/vmess.html
@@ -4,10 +4,10 @@
<a-collapse-panel header='{{ i18n "pages.inbounds.client" }}'>
<a-form-item>
<span slot="label">
- <span>{{ i18n "pages.inbounds.Email" }}</span>
+ <span>{{ i18n "pages.inbounds.email" }}</span>
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.EmailDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.emailDesc" }}</span>
</template>
<a-icon type="sync" @click="getNewEmail(client)"></a-icon>
</a-tooltip>
diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html
index cfaddf3b..d9d0637c 100644
--- a/web/html/xui/inbound_info_modal.html
+++ b/web/html/xui/inbound_info_modal.html
@@ -114,6 +114,7 @@
<tr v-if="infoModal.clientSettings.subId">
<td>Subscription link</td>
<td><a :href="[[ subBase + infoModal.clientSettings.subId ]]" target="_blank">[[ subBase + infoModal.clientSettings.subId ]]</a></td>
+ <td><a-icon id="copy-sub-link" type="snippets" @click="copyToClipboard('copy-sub-link', subBase + infoModal.clientSettings.subId)"></a-icon></td>
</tr>
<tr v-if="infoModal.clientSettings.tgId">
<td>Telegram ID</td>
@@ -190,7 +191,7 @@
<div v-if="dbInbound.hasLink()">
<a-divider>URL</a-divider>
<p>[[ infoModal.link ]]</p>
- <button class="ant-btn ant-btn-primary" id="copy-url-link"><a-icon type="snippets"></a-icon>{{ i18n "copy" }}</button>
+ <button class="ant-btn ant-btn-primary" id="copy-url-link" @click="copyToClipboard('copy-url-link', infoModal.link)"><a-icon type="snippets"></a-icon>{{ i18n "copy" }}</button>
</div>
</a-modal>
<script>
@@ -218,14 +219,6 @@
this.isExpired = this.inbound.isExpiry(index);
this.clientStats = this.settings.clients ? this.dbInbound.clientStats.find(row => row.email === this.clientSettings.email) : [];
this.visible = true;
- infoModalApp.$nextTick(() => {
- if (this.clipboard === null) {
- this.clipboard = new ClipboardJS('#copy-url-link', {
- text: () => this.link,
- });
- this.clipboard.on('success', () => app.$message.success('{{ i18n "copied" }}'));
- }
- });
},
close() {
infoModal.visible = false;
@@ -263,7 +256,7 @@
},
},
methods: {
- copyTextToClipboard(elmentId, content) {
+ copyToClipboard(elmentId, content) {
this.infoModal.clipboard = new ClipboardJS('#' + elmentId, {
text: () => content,
});
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index 080a08cc..a80fe79a 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -338,7 +338,7 @@
},
async getDBInbounds() {
this.refreshing = true;
- const msg = await HttpUtil.post('/xui/inbound/list');
+ const msg = await HttpUtil.post('/panel/inbound/list');
if (!msg.success) {
return;
}
@@ -346,7 +346,7 @@
this.refreshing = false;
},
async getDefaultSettings() {
- const msg = await HttpUtil.post('/xui/setting/defaultSettings');
+ const msg = await HttpUtil.post('/panel/setting/defaultSettings');
if (!msg.success) {
return;
}
@@ -509,7 +509,7 @@
streamSettings: baseInbound.stream.toString(),
sniffing: baseInbound.canSniffing() ? baseInbound.sniffing.toString() : '{}',
};
- await this.submit('/xui/inbound/add', data, inModal);
+ await this.submit('/panel/inbound/add', data, inModal);
},
openAddInbound() {
inModal.show({
@@ -558,7 +558,7 @@
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
if (inbound.canSniffing()) data.sniffing = inbound.sniffing.toString();
- await this.submit('/xui/inbound/add', data, inModal);
+ await this.submit('/panel/inbound/add', data, inModal);
},
async updateInbound(inbound, dbInbound) {
const data = {
@@ -577,7 +577,7 @@
if (inbound.canEnableStream()) data.streamSettings = inbound.stream.toString();
if (inbound.canSniffing()) data.sniffing = inbound.sniffing.toString();
- await this.submit(`/xui/inbound/update/${dbInbound.id}`, data, inModal);
+ await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
},
openAddClient(dbInboundId) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
@@ -632,14 +632,14 @@
id: dbInboundId,
settings: '{"clients": [' + clients.toString() + ']}',
};
- await this.submit(`/xui/inbound/addClient`, data);
+ await this.submit(`/panel/inbound/addClient`, data);
},
async updateClient(client, dbInboundId, clientId) {
const data = {
id: dbInboundId,
settings: '{"clients": [' + client.toString() + ']}',
};
- await this.submit(`/xui/inbound/updateClient/${clientId}`, data);
+ await this.submit(`/panel/inbound/updateClient/${clientId}`, data);
},
resetTraffic(dbInboundId) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
@@ -664,7 +664,7 @@
class: themeSwitcher.darkCardClass,
okText: '{{ i18n "delete"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/xui/inbound/del/' + dbInboundId),
+ onOk: () => this.submit('/panel/inbound/del/' + dbInboundId),
});
},
delClient(dbInboundId, client) {
@@ -676,7 +676,7 @@
class: themeSwitcher.darkCardClass,
okText: '{{ i18n "delete"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit(`/xui/inbound/${dbInboundId}/delClient/${clientId}`),
+ onOk: () => this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`),
});
},
getClients(protocol, clientSettings) {
@@ -696,15 +696,16 @@
}
},
showQrcode(dbInbound, clientIndex) {
+ const clientName = JSON.parse(dbInbound.settings).clients[clientIndex].email;
const link = dbInbound.genLink(clientIndex);
- qrModal.show('{{ i18n "qrCode"}}', link, dbInbound);
+ qrModal.show('{{ i18n "qrCode"}}', link, dbInbound, '', clientName);
},
showInfo(dbInbound, index) {
infoModal.show(dbInbound, index);
},
switchEnable(dbInboundId) {
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
- this.submit(`/xui/inbound/update/${dbInboundId}`, dbInbound);
+ this.submit(`/panel/inbound/update/${dbInboundId}`, dbInbound);
},
async switchEnableClient(dbInboundId, client) {
this.loading()
@@ -741,7 +742,7 @@
class: themeSwitcher.darkCardClass,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/xui/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email),
+ onOk: () => this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email),
})
},
resetAllTraffic() {
@@ -751,7 +752,7 @@
class: themeSwitcher.darkCardClass,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/xui/inbound/resetAllTraffics'),
+ onOk: () => this.submit('/panel/inbound/resetAllTraffics'),
});
},
resetAllClientTraffics(dbInboundId) {
@@ -761,7 +762,7 @@
class: themeSwitcher.darkCardClass,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/xui/inbound/resetAllClientTraffics/' + dbInboundId),
+ onOk: () => this.submit('/panel/inbound/resetAllClientTraffics/' + dbInboundId),
})
},
delDepletedClients(dbInboundId) {
@@ -771,7 +772,7 @@
class: themeSwitcher.darkCardClass,
okText: '{{ i18n "reset"}}',
cancelText: '{{ i18n "cancel"}}',
- onOk: () => this.submit('/xui/inbound/delDepletedClients/' + dbInboundId),
+ onOk: () => this.submit('/panel/inbound/delDepletedClients/' + dbInboundId),
})
},
isExpiry(dbInbound, index) {
diff --git a/web/html/xui/index.html b/web/html/xui/index.html
index 73936b29..fa7d576e 100644
--- a/web/html/xui/index.html
+++ b/web/html/xui/index.html
@@ -500,7 +500,7 @@
return;
}
this.loading(true);
- const restartMsg = await HttpUtil.post("/xui/setting/restartPanel");
+ const restartMsg = await HttpUtil.post("/panel/setting/restartPanel");
this.loading(false);
if (restartMsg.success) {
this.loading(true);
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index d50822c2..9dec0e0c 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -153,6 +153,7 @@
<setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigPrivateIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigPrivateIpDesc"}}' v-model="privateIpSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigAds"}}' desc='{{ i18n "pages.settings.templates.xrayConfigAdsDesc"}}' v-model="AdsSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigPorn"}}' desc='{{ i18n "pages.settings.templates.xrayConfigPornDesc"}}' v-model="PornSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigSpeedtest"}}' desc='{{ i18n "pages.settings.templates.xrayConfigSpeedtestDesc"}}' v-model="SpeedTestSettings"></setting-list-item>
</a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.settings.templates.countryConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
@@ -285,6 +286,7 @@
"geosite:spotify-ads"
],
porn: ["geosite:category-porn"],
+ speedtest: ["geosite:speedtest"],
openai: ["geosite:openai"],
google: ["geosite:google"],
spotify: ["geosite:spotify"],
@@ -307,13 +309,16 @@
},
}
},
+ created() {
+ this.checkForGeosites();
+ },
methods: {
loading(spinning = true, obj) {
if (obj == null) this.spinning = spinning;
},
async getAllSetting() {
this.loading(true);
- const msg = await HttpUtil.post("/xui/setting/all");
+ const msg = await HttpUtil.post("/panel/setting/all");
this.loading(false);
if (msg.success) {
this.oldAllSetting = new AllSetting(msg.obj);
@@ -324,7 +329,7 @@
},
async updateAllSetting() {
this.loading(true);
- const msg = await HttpUtil.post("/xui/setting/update", this.allSetting);
+ const msg = await HttpUtil.post("/panel/sett