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:
authorHo3ein <ho3ein.sanaei@gmail.com>2023-05-31 09:17:02 +0300
committerGitHub <noreply@github.com>2023-05-31 09:17:02 +0300
commit94fad02737d82817ca69f1f05872b49e769a0cb4 (patch)
tree55e7ead217c5a3e82791c0edae6ad44de1ba524f
parent8442836512d82b705e404bc1749e3000115ba550 (diff)
parentd694e6eafccad246c63264714897316f671d6428 (diff)
Merge pull request #545 from hamid-gh98/main
🔀 New Feature + Fix URLs + Some Improvements 🛠️🌐
-rw-r--r--README.md65
-rw-r--r--sub/sub.go19
-rw-r--r--web/assets/js/model/models.js3
-rw-r--r--web/assets/js/util/common.js18
-rw-r--r--web/controller/inbound.go2
-rw-r--r--web/controller/setting.go97
-rw-r--r--web/entity/entity.go1
-rw-r--r--web/global/hashStorage.go2
-rw-r--r--web/html/common/qrcode_modal.html30
-rw-r--r--web/html/xui/inbound_info_modal.html8
-rw-r--r--web/html/xui/inbound_modal.html2
-rw-r--r--web/html/xui/inbounds.html2
-rw-r--r--web/html/xui/settings.html59
-rw-r--r--web/middleware/domainValidator.go21
-rw-r--r--web/middleware/redirect.go34
-rw-r--r--web/service/inbound.go1
-rw-r--r--web/service/setting.go7
-rw-r--r--web/service/tgbot.go47
-rw-r--r--web/translation/translate.en_US.toml7
-rw-r--r--web/translation/translate.fa_IR.toml7
-rw-r--r--web/translation/translate.ru_RU.toml7
-rw-r--r--web/translation/translate.zh_Hans.toml7
-rw-r--r--web/web.go34
23 files changed, 274 insertions, 206 deletions
diff --git a/README.md b/README.md
index 56c4b344..9ba7e289 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@
[![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html)
3x-ui panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese,Russian)**
-
**If you think this project is helpful to you, you may wish to give a** :star2:
**Buy Me a Coffee :**
@@ -24,11 +23,12 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
# Install custom version
-To install your desired version you can add the version to the end of install command. Example for ver `v1.6.0`:
+To install your desired version you can add the version to the end of install command. Example for ver `v1.6.1`:
```
-bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.6.0
+bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.6.1
```
+
# SSL
```
@@ -37,8 +37,8 @@ certbot certonly --standalone --agree-tos --register-unsafely-without-email -d y
certbot renew --dry-run
```
-or you can use x-ui menu then number `16` (`SSL Certificate Management`)
-
+You also can use `x-ui` menu then select `16. SSL Certificate Management`
+
# Features
- System Status Monitoring
@@ -57,23 +57,26 @@ or you can use x-ui menu then number `16` (`SSL Certificate Management`)
- Support export/import database from panel
# Manual Install & Upgrade
+
<details>
<summary>Click for Manual Install details</summary>
-
+
1. To download the latest version of the compressed package directly to your server, run the following command:
```sh
-wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-amd64.tar.gz
+ARCH=$(uname -m)
+[[ "${ARCH}" == "aarch64" || "${ARCH}" == "arm64" ]] && XUI_ARCH="arm64" || XUI_ARCH="amd64"
+wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
```
-Note: If your server's CPU architecture is `arm64`, modify the URL by substituting `amd64` with your respective CPU architecture.
-
2. Once the compressed package is downloaded, execute the following commands to install or upgrade x-ui:
```sh
+ARCH=$(uname -m)
+[[ "${ARCH}" == "aarch64" || "${ARCH}" == "arm64" ]] && XUI_ARCH="arm64" || XUI_ARCH="amd64"
cd /root/
rm -rf x-ui/ /usr/local/x-ui/ /usr/bin/x-ui
-tar zxvf x-ui-linux-amd64.tar.gz
+tar zxvf x-ui-linux-${XUI_ARCH}.tar.gz
chmod +x x-ui/x-ui x-ui/bin/xray-linux-* x-ui/x-ui.sh
cp x-ui/x-ui.sh /usr/bin/x-ui
cp -f x-ui/x-ui.service /etc/systemd/system/
@@ -82,14 +85,16 @@ systemctl daemon-reload
systemctl enable x-ui
systemctl restart x-ui
```
-Note: If your server's CPU architecture is `arm64`, modify the `amd64` in `tar zxvf x-ui-linux-amd64.tar.gz` with your respective CPU architecture.
+
</details>
-
+
# Install with Docker
+
<details>
<summary>Click for Docker details</summary>
1. Install Docker:
+
```sh
bash <(curl -sSL https://get.docker.com)
```
@@ -100,7 +105,7 @@ Note: If your server's CPU architecture is `arm64`, modify the `amd64` in `tar z
git clone https://github.com/MHSanaei/3x-ui.git
cd 3x-ui
```
-
+
3. Start the Service
```sh
@@ -119,12 +124,14 @@ Note: If your server's CPU architecture is `arm64`, modify the `amd64` in `tar z
--name 3x-ui \
ghcr.io/mhsanaei/3x-ui:latest
```
+
</details>
-
+
# Default settings
+
<details>
<summary>Click for Default settings details</summary>
-
+
- Port: 2053
- username and password will be generated randomly if you skip to modify your own security(x-ui "7")
- database path: /etc/x-ui/x-ui.db
@@ -141,10 +148,10 @@ After you set ssl on settings
</details>
# Xray Configurations:
-
+
<details>
<summary>Click for Xray Configurations details</summary>
-
+
**copy and paste to xray Configuration :** (you don't need to do this if you have a fresh install)
- [traffic](./media/configs/traffic.json)
@@ -152,14 +159,14 @@ After you set ssl on settings
- [traffic + Block all Iran Domains](./media/configs/traffic+block-iran-domains.json)
- [traffic + Block Ads + Use IPv4 for Google](./media/configs/traffic+block-ads+ipv4-google.json)
- [traffic + Block Ads + Route Google + Netflix + Spotify + OpenAI (ChatGPT) to WARP](./media/configs/traffic+block-ads+warp.json)
-
+
</details>
-
+
# [WARP Configuration](https://github.com/fscarmen/warp) (Optional)
-
+
<details>
<summary>Click for WARP Configuration details</summary>
-
+
If you want to use routing to WARP follow steps as below:
1. If you already installed warp, you can uninstall using below command:
@@ -171,7 +178,7 @@ If you want to use routing to WARP follow steps as below:
2. Install WARP on **socks proxy mode**:
```sh
- curl -fsSL https://gist.githubusercontent.com/hamid-gh98/dc5dd9b0cc5b0412af927b1ccdb294c7/raw/install_warp_proxy.sh | bash
+ bash <(curl -sSL https://gist.githubusercontent.com/hamid-gh98/dc5dd9b0cc5b0412af927b1ccdb294c7/raw/install_warp_proxy.sh)
```
3. Turn on the config you need in panel or [Copy and paste this file to Xray Configuration](./media/configs/traffic+block-ads+warp.json)
@@ -181,14 +188,14 @@ If you want to use routing to WARP follow steps as below:
- Block Ads
- Route Google + Netflix + Spotify + OpenAI (ChatGPT) to WARP
- Fix Google 403 error
-
+
</details>
# Telegram Bot
-
+
<details>
<summary>Click for Telegram Bot details</summary>
-
+
X-UI supports daily traffic notification, panel login reminder and other functions through the Tg robot. To use the Tg robot, you need to apply for the specific application tutorial. You can refer to the [blog](https://coderfan.net/how-to-use-telegram-bot-to-alarm-you-when-someone-login-into-your-vps.html)
Set the robot-related parameters in the panel background, including:
@@ -216,19 +223,21 @@ Reference syntax:
- CPU threshold notification
- Threshold for Expiration time and Traffic to report in advance
- Support client report menu if client's telegram username added to the user's configurations
-- Support telegram traffic report searched with UID (VMESS/VLESS) or Password (TROJAN) - anonymously
+- Support telegram traffic report searched with UUID (VMESS/VLESS) or Password (TROJAN) - anonymously
- Menu based bot
- Search client by email ( only admin )
- Check all inbounds
- Check server status
- Check depleted users
- Receive backup by request and in periodic reports
+- Multi language bot
</details>
# API routes
+
<details>
<summary>Click for API routes details</summary>
-
+
- `/login` with `PUSH` user data: `{username: '', password: ''}` for login
- `/panel/api/inbounds` base for following actions:
@@ -261,6 +270,7 @@ Reference syntax:
</details>
# Environment Variables
+
<details>
<summary>Click for Environment Variables details</summary>
@@ -276,6 +286,7 @@ Example:
```sh
XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
```
+
</details>
# A Special Thanks To
diff --git a/sub/sub.go b/sub/sub.go
index f7353cc2..b642f7f2 100644
--- a/sub/sub.go
+++ b/sub/sub.go
@@ -7,10 +7,10 @@ import (
"net"
"net/http"
"strconv"
- "strings"
"x-ui/config"
"x-ui/logger"
"x-ui/util/common"
+ "x-ui/web/middleware"
"x-ui/web/network"
"x-ui/web/service"
@@ -58,18 +58,7 @@ func (s *Server) initRouter() (*gin.Engine, error) {
}
if subDomain != "" {
- validateDomain := func(c *gin.Context) {
- host := strings.Split(c.Request.Host, ":")[0]
-
- if host != subDomain {
- c.AbortWithStatus(http.StatusForbidden)
- return
- }
-
- c.Next()
- }
-
- engine.Use(validateDomain)
+ engine.Use(middleware.DomainValidatorMiddleware(subDomain))
}
g := engine.Group(subPath)
@@ -116,11 +105,13 @@ func (s *Server) Start() (err error) {
if err != nil {
return err
}
+
listenAddr := net.JoinHostPort(listen, strconv.Itoa(port))
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
return err
}
+
if certFile != "" || keyFile != "" {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
@@ -168,4 +159,4 @@ func (s *Server) Stop() error {
func (s *Server) GetCtx() context.Context {
return s.ctx
-} \ No newline at end of file
+}
diff --git a/web/assets/js/model/models.js b/web/assets/js/model/models.js
index 9a5dcc85..e1a766dc 100644
--- a/web/assets/js/model/models.js
+++ b/web/assets/js/model/models.js
@@ -168,6 +168,7 @@ class AllSetting {
constructor(data) {
this.webListen = "";
+ this.webDomain = "";
this.webPort = 2053;
this.webCertFile = "";
this.webKeyFile = "";
@@ -187,7 +188,7 @@ class AllSetting {
this.subEnable = false;
this.subListen = "";
this.subPort = "2096";
- this.subPath = "sub/";
+ this.subPath = "/sub/";
this.subDomain = "";
this.subCertFile = "";
this.subKeyFile = "";
diff --git a/web/assets/js/util/common.js b/web/assets/js/util/common.js
index 563bfd45..8e30bce7 100644
--- a/web/assets/js/util/common.js
+++ b/web/assets/js/util/common.js
@@ -135,3 +135,21 @@ function doAllItemsExist(array1, array2) {
}
return true;
}
+
+function buildURL({ host, port, isTLS, base, path }) {
+ if (!host || host.length === 0) host = window.location.hostname;
+ if (!port || port.length === 0) port = window.location.port;
+
+ if (isTLS === undefined) isTLS = window.location.protocol === "https:";
+
+ const protocol = isTLS ? "https:" : "http:";
+
+ port = String(port);
+ if (port === "" || (isTLS && port === "443") || (!isTLS && port === "80")) {
+ port = "";
+ } else {
+ port = `:${port}`;
+ }
+
+ return `${protocol}//${host}${port}${base}${path}`;
+}
diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index 5ce58d53..815f1788 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -65,6 +65,7 @@ func (a *InboundController) getInbounds(c *gin.Context) {
}
jsonObj(c, inbounds, nil)
}
+
func (a *InboundController) getInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
@@ -168,6 +169,7 @@ func (a *InboundController) clearClientIps(c *gin.Context) {
}
jsonMsg(c, "Log Cleared", nil)
}
+
func (a *InboundController) addInboundClient(c *gin.Context) {
data := &model.Inbound{}
err := c.ShouldBind(data)
diff --git a/web/controller/setting.go b/web/controller/setting.go
index 0292c46a..cd509293 100644
--- a/web/controller/setting.go
+++ b/web/controller/setting.go
@@ -65,77 +65,42 @@ func (a *SettingController) getDefaultJsonConfig(c *gin.Context) {
}
func (a *SettingController) getDefaultSettings(c *gin.Context) {
- expireDiff, err := a.settingService.GetExpireDiff()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- trafficDiff, err := a.settingService.GetTrafficDiff()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- defaultCert, err := a.settingService.GetCertFile()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- defaultKey, err := a.settingService.GetKeyFile()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- tgBotEnable, err := a.settingService.GetTgbotenabled()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- subEnable, err := a.settingService.GetSubEnable()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- subPort, err := a.settingService.GetSubPort()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- subPath, err := a.settingService.GetSubPath()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- subDomain, err := a.settingService.GetSubDomain()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
- }
- subKeyFile, err := a.settingService.GetSubKeyFile()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
+ type settingFunc func() (interface{}, error)
+
+ settings := map[string]settingFunc{
+ "expireDiff": func() (interface{}, error) { return a.settingService.GetExpireDiff() },
+ "trafficDiff": func() (interface{}, error) { return a.settingService.GetTrafficDiff() },
+ "defaultCert": func() (interface{}, error) { return a.settingService.GetCertFile() },
+ "defaultKey": func() (interface{}, error) { return a.settingService.GetKeyFile() },
+ "tgBotEnable": func() (interface{}, error) { return a.settingService.GetTgbotenabled() },
+ "subEnable": func() (interface{}, error) { return a.settingService.GetSubEnable() },
+ "subPort": func() (interface{}, error) { return a.settingService.GetSubPort() },
+ "subPath": func() (interface{}, error) { return a.settingService.GetSubPath() },
+ "subDomain": func() (interface{}, error) { return a.settingService.GetSubDomain() },
+ "subKeyFile": func() (interface{}, error) { return a.settingService.GetSubKeyFile() },
+ "subCertFile": func() (interface{}, error) { return a.settingService.GetSubCertFile() },
}
- subCertFile, err := a.settingService.GetSubCertFile()
- if err != nil {
- jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
- return
+
+ result := make(map[string]interface{})
+
+ for key, fn := range settings {
+ value, err := fn()
+ if err != nil {
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
+ return
+ }
+ result[key] = value
}
+
subTLS := false
- if subKeyFile != "" || subCertFile != "" {
+ if result["subKeyFile"] != "" || result["subCertFile"] != "" {
subTLS = true
}
- result := map[string]interface{}{
- "expireDiff": expireDiff,
- "trafficDiff": trafficDiff,
- "defaultCert": defaultCert,
- "defaultKey": defaultKey,
- "tgBotEnable": tgBotEnable,
- "subEnable": subEnable,
- "subPort": subPort,
- "subPath": subPath,
- "subDomain": subDomain,
- "subTLS": subTLS,
- }
+ result["subTLS"] = subTLS
+
+ delete(result, "subKeyFile")
+ delete(result, "subCertFile")
+
jsonObj(c, result, nil)
}
diff --git a/web/entity/entity.go b/web/entity/entity.go
index 0bfbfd2a..d5e90108 100644
--- a/web/entity/entity.go
+++ b/web/entity/entity.go
@@ -28,6 +28,7 @@ type Pager struct {
type AllSetting struct {
WebListen string `json:"webListen" form:"webListen"`
+ WebDomain string `json:"webDomain" form:"webDomain"`
WebPort int `json:"webPort" form:"webPort"`
WebCertFile string `json:"webCertFile" form:"webCertFile"`
WebKeyFile string `json:"webKeyFile" form:"webKeyFile"`
diff --git a/web/global/hashStorage.go b/web/global/hashStorage.go
index 9dfea169..5d8135ee 100644
--- a/web/global/hashStorage.go
+++ b/web/global/hashStorage.go
@@ -18,7 +18,6 @@ type HashStorage struct {
sync.RWMutex
Data map[string]HashEntry
Expiration time.Duration
-
}
func NewHashStorage(expiration time.Duration) *HashStorage {
@@ -46,7 +45,6 @@ func (h *HashStorage) SaveHash(query string) string {
return md5HashString
}
-
func (h *HashStorage) GetValue(hash string) (string, bool) {
h.RLock()
defer h.RUnlock()
diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html
index e6b7b998..8edfa2de 100644
--- a/web/html/common/qrcode_modal.html
+++ b/web/html/common/qrcode_modal.html
@@ -68,8 +68,8 @@
qrModal: qrModal,
},
methods: {
- copyToClipboard(elmentId,content) {
- this.qrModal.clipboard = new ClipboardJS('#'+elmentId, {
+ copyToClipboard(elmentId, content) {
+ this.qrModal.clipboard = new ClipboardJS('#' + elmentId, {
text: () => content,
});
this.qrModal.clipboard.on('success', () => {
@@ -77,29 +77,25 @@
this.qrModal.clipboard.destroy();
});
},
- setQrCode(elmentId,content) {
+ setQrCode(elmentId, content) {
new QRious({
- element: document.querySelector('#'+elmentId),
- size: 260,
- value: content,
- });
+ element: document.querySelector('#' + elmentId),
+ size: 260,
+ value: content,
+ });
},
genSubLink(subID) {
- protocol = app.subSettings.tls ? "https://" : "http://";
- hostName = app.subSettings.domain === "" ? window.location.hostname : app.subSettings.domain;
- subPort = app.subSettings.port;
- port = (subPort === 443 && app.subSettings.tls) || (subPort === 80 && !app.subSettings.tls) ? "" : ":" + String(subPort);
- subPath = app.subSettings.path;
- return protocol + hostName + port + subPath + subID;
+ const { domain: host, port, tls: isTLS, path: base } = app.subSettings;
+ return buildURL({ host, port, isTLS, base, path: subID });
}
},
updated() {
- if (qrModal.client.subId){
+ if (qrModal.client && qrModal.client.subId) {
qrModal.subId = qrModal.client.subId;
- this.setQrCode("qrCode-sub",this.genSubLink(qrModal.subId));
+ this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId));
}
- qrModal.qrcodes.forEach((element,index) => {
- this.setQrCode("qrCode-"+index, element.link);
+ qrModal.qrcodes.forEach((element, index) => {
+ this.setQrCode("qrCode-" + index, element.link);
});
}
});
diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html
index b7b3436b..23bd5af1 100644
--- a/web/html/xui/inbound_info_modal.html
+++ b/web/html/xui/inbound_info_modal.html
@@ -253,12 +253,8 @@
infoModal.visible = false;
},
genSubLink(subID) {
- protocol = app.subSettings.tls ? "https://" : "http://";
- hostName = app.subSettings.domain === "" ? window.location.hostname : app.subSettings.domain;
- subPort = app.subSettings.port;
- port = (subPort === 443 && app.subSettings.tls) || (subPort === 80 && !app.subSettings.tls) ? "" : ":" + String(subPort);
- subPath = app.subSettings.path;
- return protocol + hostName + port + subPath + subID;
+ const { domain: host, port, tls: isTLS, path: base } = app.subSettings;
+ return buildURL({ host, port, isTLS, base, path: subID });
}
};
diff --git a/web/html/xui/inbound_modal.html b/web/html/xui/inbound_modal.html
index 25e19473..11e6020c 100644
--- a/web/html/xui/inbound_modal.html
+++ b/web/html/xui/inbound_modal.html
@@ -96,7 +96,7 @@
set multiDomain(value) {
if (value) {
inModal.inbound.stream.tls.server = "";
- inModal.inbound.stream.tls.settings.domains = [{remark: "", domain: window.location.host.split(":")[0]}];
+ inModal.inbound.stream.tls.settings.domains = [{ remark: "", domain: window.location.hostname }];
} else {
inModal.inbound.stream.tls.server = "";
inModal.inbound.stream.tls.settings.domains = [];
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index 7b9ba207..329f0f46 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -311,7 +311,7 @@
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 120, scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
- { title: 'UID', width: 120, dataIndex: "id" },
+ { title: 'UUID', width: 120, dataIndex: "id" },
];
const innerTrojanColumns = [
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index d78533a1..745959a2 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -91,6 +91,7 @@
</a-row>
<a-list item-layout="horizontal" :style="themeSwitcher.textStyle">
<setting-list-item type="text" title='{{ i18n "pages.settings.panelListeningIP"}}' desc='{{ i18n "pages.settings.panelListeningIPDesc"}}' v-model="allSetting.webListen"></setting-list-item>
+ <setting-list-item type="text" title='{{ i18n "pages.settings.panelListeningDomain"}}' desc='{{ i18n "pages.settings.panelListeningDomainDesc"}}' v-model="allSetting.webDomain"></setting-list-item>
<setting-list-item type="number" title='{{ i18n "pages.settings.panelPort"}}' desc='{{ i18n "pages.settings.panelPortDesc"}}' v-model="allSetting.webPort" :min="0"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.publicKeyPath"}}' desc='{{ i18n "pages.settings.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.privateKeyPath"}}' desc='{{ i18n "pages.settings.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
@@ -306,23 +307,37 @@
<setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigNetflixWARP"}}' desc='{{ i18n "pages.settings.templates.xrayConfigNetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
<setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigSpotifyWARP"}}' desc='{{ i18n "pages.settings.templates.xrayConfigSpotifyWARPDesc"}}' v-model="SpotifyWARPSettings"></setting-list-item>
</a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.settings.templates.manualLists"}}'>
- <a-row :xs="24" :sm="24" :lg="12">
- <h2 class="collapse-title">
- <a-icon type="warning"></a-icon>
- {{ i18n "pages.settings.templates.manualListsDesc" }}
- </h2>
- </a-row>
- <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.manualBlockedIPs"}}' v-model="manualBlockedIPs"></setting-list-item>
- <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.manualBlockedDomains"}}' v-model="manualBlockedDomains"></setting-list-item>
- <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.manualDirectIPs"}}' v-model="manualDirectIPs"></setting-list-item>
- <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.manualDirectDomains"}}' v-model="manualDirectDomains"></setting-list-item>
- <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.manualIPv4Domains"}}' v-model="manualIPv4Domains"></setting-list-item>
- <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.manualWARPDomains"}}' v-model="manualWARPDomains"></setting-list-item>
+ </a-collapse>
+ </a-tab-pane>
+ <a-tab-pane key="tpl-2" tab='{{ i18n "pages.settings.templates.manualLists"}}' style="padding-top: 20px;">
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.manualListsDesc" }}
+ </h2>
+ </a-row>
+ <a-collapse>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualBlockedIPs"}}'>
+ <setting-list-item type="textarea" v-model="manualBlockedIPs"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualBlockedDomains"}}'>
+ <setting-list-item type="textarea" v-model="manualBlockedDomains"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualDirectIPs"}}'>
+ <setting-list-item type="textarea" v-model="manualDirectIPs"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualDirectDomains"}}'>
+ <setting-list-item type="textarea" v-model="manualDirectDomains"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualIPv4Domains"}}'>
+ <setting-list-item type="textarea" v-model="manualIPv4Domains"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualWARPDomains"}}'>
+ <setting-list-item type="textarea" v-model="manualWARPDomains"></setting-list-item>
</a-collapse-panel>
</a-collapse>
</a-tab-pane>
- <a-tab-pane key="tpl-2" tab='{{ i18n "pages.settings.templates.advancedTemplate"}}' style="padding-top: 20px;">
+ <a-tab-pane key="tpl-3" tab='{{ i18n "pages.settings.templates.advancedTemplate"}}' style="padding-top: 20px;">
<a-collapse>
<a-collapse-panel header='{{ i18n "pages.settings.templates.xrayConfigInbounds"}}'>
<setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.xrayConfigInbounds"}}' desc='{{ i18n "pages.settings.templates.xrayConfigInboundsDesc"}}' v-model="inboundSettings"></setting-list-item>
@@ -335,7 +350,7 @@
</a-collapse-panel>
</a-collapse>
</a-tab-pane>
- <a-tab-pane key="tpl-3" tab='{{ i18n "pages.settings.templates.completeTemplate"}}' style="padding-top: 20px;">
+ <a-tab-pane key="tpl-4" tab='{{ i18n "pages.settings.templates.completeTemplate"}}' style="padding-top: 20px;">
<setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.xrayConfigTemplate"}}' desc='{{ i18n "pages.settings.templates.xrayConfigTemplateDesc"}}' v-model="allSetting.xrayTemplateConfig"></setting-list-item>
</a-tab-pane>
</a-tabs>
@@ -391,9 +406,9 @@
<a-list item-layout="horizontal" :style="themeSwitcher.textStyle">
<setting-list-item type="switch" title='{{ i18n "pages.settings.subEnable"}}' desc='{{ i18n "pages.settings.subEnableDesc"}}' v-model="allSetting.subEnable"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.subListen"}}' desc='{{ i18n "pages.settings.subListenDesc"}}' v-model="allSetting.subListen"></setting-list-item>
+ <setting-list-item type="text" title='{{ i18n "pages.settings.subDomain"}}' desc='{{ i18n "pages.settings.subDomainDesc"}}' v-model="allSetting.subDomain"></setting-list-item>
<setting-list-item type="number" title='{{ i18n "pages.settings.subPort"}}' desc='{{ i18n "pages.settings.subPortDesc"}}' v-model.number="allSetting.subPort"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subPath"></setting-list-item>
- <setting-list-item type="text" title='{{ i18n "pages.settings.subDomain"}}' desc='{{ i18n "pages.settings.subDomainDesc"}}' v-model="allSetting.subDomain"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.subCertPath"}}' desc='{{ i18n "pages.settings.subCertPathDesc"}}' v-model="allSetting.subCertFile"></setting-list-item>
<setting-list-item type="text" title='{{ i18n "pages.settings.subKeyPath"}}' desc='{{ i18n "pages.settings.subKeyPathDesc"}}' v-model="allSetting.subKeyFile"></setting-list-item>
<setting-list-item type="number" title='{{ i18n "pages.settings.subUpdates"}}' desc='{{ i18n "pages.settings.subUpdatesDesc"}}' v-model="allSetting.subUpdates"></setting-list-item>
@@ -522,7 +537,7 @@
this.loading(false);
if (msg.success) {
this.user = {};
- window.location.replace(basePath + "logout")
+ window.location.replace(bas