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--.gitignore16
-rw-r--r--README.md1
-rw-r--r--web/assets/js/model/models.js1
-rw-r--r--web/controller/api.go2
-rw-r--r--web/controller/base.go20
-rw-r--r--web/controller/inbound.go32
-rw-r--r--web/controller/index.go15
-rw-r--r--web/controller/server.go4
-rw-r--r--web/controller/setting.go30
-rw-r--r--web/controller/util.go6
-rw-r--r--web/entity/entity.go1
-rw-r--r--web/global/hashStorage.go82
-rw-r--r--web/html/xui/form/tls_settings.html6
-rw-r--r--web/html/xui/inbounds.html8
-rw-r--r--web/html/xui/settings.html236
-rw-r--r--web/job/check_cpu_usage.go7
-rw-r--r--web/job/check_hash_storage.go19
-rw-r--r--web/locale/locale.go144
-rw-r--r--web/network/auto_https_conn.go (renamed from web/network/autp_https_conn.go)0
-rw-r--r--web/service/setting.go5
-rw-r--r--web/service/sub.go3
-rw-r--r--web/service/tgbot.go597
-rw-r--r--web/translation/translate.en_US.toml116
-rw-r--r--web/translation/translate.fa_IR.toml114
-rw-r--r--web/translation/translate.ru_RU.toml114
-rw-r--r--web/translation/translate.zh_Hans.toml114
-rw-r--r--web/web.go115
27 files changed, 1315 insertions, 493 deletions
diff --git a/.gitignore b/.gitignore
index 6277cfc9..158f4ee1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,15 @@
.idea
.vscode
+.cache
+.sync*
+*.tar.gz
+access.log
+error.log
tmp
+main
backup/
bin/
dist/
-x-ui-*.tar.gz
-/x-ui
-/release.sh
-.sync*
-main
release/
-access.log
-error.log
-.cache
+/release.sh
+/x-ui
diff --git a/README.md b/README.md
index d39494ca..54966a43 100644
--- a/README.md
+++ b/README.md
@@ -194,6 +194,7 @@ Reference syntax:
| `GET` | `"/list"` | Get all inbounds |
| `GET` | `"/get/:id"` | Get inbound with inbound.id |
| `GET` | `"/getClientTraffics/:email"` | Get Client Traffics with email |
+| `GET` | `"/createbackup"` | Telegram bot sends backup to admins |
| `POST` | `"/add"` | Add inbound |
| `POST` | `"/del/:id"` | Delete Inbound |
| `POST` | `"/update/:id"` | Update Inbound |
diff --git a/web/assets/js/model/models.js b/web/assets/js/model/models.js
index a3fd2633..e1fb5d02 100644
--- a/web/assets/js/model/models.js
+++ b/web/assets/js/model/models.js
@@ -181,6 +181,7 @@ class AllSetting {
this.tgRunTime = "@daily";
this.tgBotBackup = false;
this.tgCpu = "";
+ this.tgLang = "";
this.xrayTemplateConfig = "";
this.secretEnable = false;
diff --git a/web/controller/api.go b/web/controller/api.go
index 17073345..32c639f8 100644
--- a/web/controller/api.go
+++ b/web/controller/api.go
@@ -102,5 +102,5 @@ func (a *APIController) delDepletedClients(c *gin.Context) {
}
func (a *APIController) createBackup(c *gin.Context) {
- a.Tgbot.SendBackUP(c)
+ a.Tgbot.SendBackupToAdmins()
}
diff --git a/web/controller/base.go b/web/controller/base.go
index 98e1831c..674a195d 100644
--- a/web/controller/base.go
+++ b/web/controller/base.go
@@ -2,6 +2,8 @@ package controller
import (
"net/http"
+ "x-ui/logger"
+ "x-ui/web/locale"
"x-ui/web/session"
"github.com/gin-gonic/gin"
@@ -13,7 +15,7 @@ type BaseController struct {
func (a *BaseController) checkLogin(c *gin.Context) {
if !session.IsLogin(c) {
if isAjax(c) {
- pureJsonMsg(c, false, I18n(c, "pages.login.loginAgain"))
+ pureJsonMsg(c, false, I18nWeb(c, "pages.login.loginAgain"))
} else {
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
}
@@ -23,11 +25,13 @@ func (a *BaseController) checkLogin(c *gin.Context) {
}
}
-func I18n(c *gin.Context, name string) string {
- anyfunc, _ := c.Get("I18n")
- i18n, _ := anyfunc.(func(key string, params ...string) (string, error))
-
- message, _ := i18n(name)
-
- return message
+func I18nWeb(c *gin.Context, name string, params ...string) string {
+ anyfunc, funcExists := c.Get("I18n")
+ if !funcExists {
+ logger.Warning("I18n function not exists in gin context!")
+ return ""
+ }
+ i18nFunc, _ := anyfunc.(func(i18nType locale.I18nType, key string, keyParams ...string) string)
+ msg := i18nFunc(locale.Web, name, params...)
+ return msg
}
diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index 8360cf62..d13e40bc 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -60,7 +60,7 @@ func (a *InboundController) getInbounds(c *gin.Context) {
user := session.GetLoginUser(c)
inbounds, err := a.inboundService.GetInbounds(user.Id)
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.toasts.obtain"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.obtain"), err)
return
}
jsonObj(c, inbounds, nil)
@@ -68,12 +68,12 @@ func (a *InboundController) getInbounds(c *gin.Context) {
func (a *InboundController) getInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "get"), err)
+ jsonMsg(c, I18nWeb(c, "get"), err)
return
}
inbound, err := a.inboundService.GetInbound(id)
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.toasts.obtain"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.obtain"), err)
return
}
jsonObj(c, inbound, nil)
@@ -93,7 +93,7 @@ func (a *InboundController) addInbound(c *gin.Context) {
inbound := &model.Inbound{}
err := c.ShouldBind(inbound)
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.create"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.create"), err)
return
}
user := session.GetLoginUser(c)
@@ -101,7 +101,7 @@ func (a *InboundController) addInbound(c *gin.Context) {
inbound.Enable = true
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
inbound, err = a.inboundService.AddInbound(inbound)
- jsonMsgObj(c, I18n(c, "pages.inbounds.create"), inbound, err)
+ jsonMsgObj(c, I18nWeb(c, "pages.inbounds.create"), inbound, err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
@@ -110,11 +110,11 @@ func (a *InboundController) addInbound(c *gin.Context) {
func (a *InboundController) delInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "delete"), err)
+ jsonMsg(c, I18nWeb(c, "delete"), err)
return
}
err = a.inboundService.DelInbound(id)
- jsonMsgObj(c, I18n(c, "delete"), id, err)
+ jsonMsgObj(c, I18nWeb(c, "delete"), id, err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
@@ -123,7 +123,7 @@ func (a *InboundController) delInbound(c *gin.Context) {
func (a *InboundController) updateInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
inbound := &model.Inbound{
@@ -131,11 +131,11 @@ func (a *InboundController) updateInbound(c *gin.Context) {
}
err = c.ShouldBind(inbound)
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
inbound, err = a.inboundService.UpdateInbound(inbound)
- jsonMsgObj(c, I18n(c, "pages.inbounds.update"), inbound, err)
+ jsonMsgObj(c, I18nWeb(c, "pages.inbounds.update"), inbound, err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
@@ -165,7 +165,7 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
data := &model.Inbound{}
err := c.ShouldBind(data)
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
@@ -183,7 +183,7 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
func (a *InboundController) delInboundClient(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
clientId := c.Param("clientId")
@@ -205,7 +205,7 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
inbound := &model.Inbound{}
err := c.ShouldBind(inbound)
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
@@ -223,7 +223,7 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
func (a *InboundController) resetClientTraffic(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
email := c.Param("email")
@@ -251,7 +251,7 @@ func (a *InboundController) resetAllTraffics(c *gin.Context) {
func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
@@ -266,7 +266,7 @@ func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
func (a *InboundController) delDepletedClients(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
- jsonMsg(c, I18n(c, "pages.inbounds.update"), err)
+ jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
return
}
err = a.inboundService.DelDepletedClients(id)
diff --git a/web/controller/index.go b/web/controller/index.go
index ac2ceca1..0254106c 100644
--- a/web/controller/index.go
+++ b/web/controller/index.go
@@ -49,26 +49,27 @@ func (a *IndexController) login(c *gin.Context) {
var form LoginForm
err := c.ShouldBind(&form)
if err != nil {
- pureJsonMsg(c, false, I18n(c, "pages.login.toasts.invalidFormData"))
+ pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
return
}
if form.Username == "" {
- pureJsonMsg(c, false, I18n(c, "pages.login.toasts.emptyUsername"))
+ pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.emptyUsername"))
return
}
if form.Password == "" {
- pureJsonMsg(c, false, I18n(c, "pages.login.toasts.emptyPassword"))
+ pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.emptyPassword"))
return
}
+
user := a.userService.CheckUser(form.Username, form.Password, form.LoginSecret)
timeStr := time.Now().Format("2006-01-02 15:04:05")
if user == nil {
- a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
logger.Infof("wrong username or password: \"%s\" \"%s\"", form.Username, form.Password)
- pureJsonMsg(c, false, I18n(c, "pages.login.toasts.wrongUsernameOrPassword"))
+ a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
+ pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
return
} else {
- logger.Infof("%s login success,Ip Address:%s\n", form.Username, getRemoteIp(c))
+ logger.Infof("%s login success, Ip Address: %s\n", form.Username, getRemoteIp(c))
a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 1)
}
@@ -86,7 +87,7 @@ func (a *IndexController) login(c *gin.Context) {
err = session.SetLoginUser(c, user)
logger.Info("user", user.Id, "login success")
- jsonMsg(c, I18n(c, "pages.login.toasts.successLogin"), err)
+ jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), err)
}
func (a *IndexController) logout(c *gin.Context) {
diff --git a/web/controller/server.go b/web/controller/server.go
index 2db6e7fd..cc4eaacc 100644
--- a/web/controller/server.go
+++ b/web/controller/server.go
@@ -81,7 +81,7 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {
versions, err := a.serverService.GetXrayVersions()
if err != nil {
- jsonMsg(c, I18n(c, "getVersion"), err)
+ jsonMsg(c, I18nWeb(c, "getVersion"), err)
return
}
@@ -94,7 +94,7 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {
func (a *ServerController) installXray(c *gin.Context) {
version := c.Param("version")
err := a.serverService.UpdateXray(version)
- jsonMsg(c, I18n(c, "install")+" xray", err)
+ jsonMsg(c, I18nWeb(c, "install")+" xray", err)
}
func (a *ServerController) stopXrayService(c *gin.Context) {
diff --git a/web/controller/setting.go b/web/controller/setting.go
index 3aed69e6..226b7975 100644
--- a/web/controller/setting.go
+++ b/web/controller/setting.go
@@ -49,7 +49,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
func (a *SettingController) getAllSetting(c *gin.Context) {
allSetting, err := a.settingService.GetAllSetting()
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
jsonObj(c, allSetting, nil)
@@ -58,7 +58,7 @@ func (a *SettingController) getAllSetting(c *gin.Context) {
func (a *SettingController) getDefaultJsonConfig(c *gin.Context) {
defaultJsonConfig, err := a.settingService.GetDefaultJsonConfig()
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
jsonObj(c, defaultJsonConfig, nil)
@@ -67,22 +67,22 @@ func (a *SettingController) getDefaultJsonConfig(c *gin.Context) {
func (a *SettingController) getDefaultSettings(c *gin.Context) {
expireDiff, err := a.settingService.GetExpireDiff()
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
trafficDiff, err := a.settingService.GetTrafficDiff()
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
defaultCert, err := a.settingService.GetCertFile()
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
defaultKey, err := a.settingService.GetKeyFile()
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
return
}
result := map[string]interface{}{
@@ -98,27 +98,27 @@ func (a *SettingController) updateSetting(c *gin.Context) {
allSetting := &entity.AllSetting{}
err := c.ShouldBind(allSetting)
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
return
}
err = a.settingService.UpdateAllSetting(allSetting)
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
}
func (a *SettingController) updateUser(c *gin.Context) {
form := &updateUserForm{}
err := c.ShouldBind(form)
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
return
}
user := session.GetLoginUser(c)
if user.Username != form.OldUsername || user.Password != form.OldPassword {
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifyUser"), errors.New(I18n(c, "pages.settings.toasts.originalUserPassIncorrect")))
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifyUser"), errors.New(I18nWeb(c, "pages.settings.toasts.originalUserPassIncorrect")))
return
}
if form.NewUsername == "" || form.NewPassword == "" {
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifyUser"), errors.New(I18n(c, "pages.settings.toasts.userPassMustBeNotEmpty")))
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifyUser"), errors.New(I18nWeb(c, "pages.settings.toasts.userPassMustBeNotEmpty")))
return
}
err = a.userService.UpdateUser(user.Id, form.NewUsername, form.NewPassword)
@@ -127,19 +127,19 @@ func (a *SettingController) updateUser(c *gin.Context) {
user.Password = form.NewPassword
session.SetLoginUser(c, user)
}
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifyUser"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifyUser"), err)
}
func (a *SettingController) restartPanel(c *gin.Context) {
err := a.panelService.RestartPanel(time.Second * 3)
- jsonMsg(c, I18n(c, "pages.settings.restartPanel"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.restartPanel"), err)
}
func (a *SettingController) updateSecret(c *gin.Context) {
form := &updateSecretForm{}
err := c.ShouldBind(form)
if err != nil {
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
}
user := session.GetLoginUser(c)
err = a.userService.UpdateUserSecret(user.Id, form.LoginSecret)
@@ -147,7 +147,7 @@ func (a *SettingController) updateSecret(c *gin.Context) {
user.LoginSecret = form.LoginSecret
session.SetLoginUser(c, user)
}
- jsonMsg(c, I18n(c, "pages.settings.toasts.modifyUser"), err)
+ jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifyUser"), err)
}
func (a *SettingController) getUserSecret(c *gin.Context) {
diff --git a/web/controller/util.go b/web/controller/util.go
index dc5c83b0..da77189b 100644
--- a/web/controller/util.go
+++ b/web/controller/util.go
@@ -38,12 +38,12 @@ func jsonMsgObj(c *gin.Context, msg string, obj interface{}, err error) {
if err == nil {
m.Success = true
if msg != "" {
- m.Msg = msg + I18n(c, "success")
+ m.Msg = msg + I18nWeb(c, "success")
}
} else {
m.Success = false
- m.Msg = msg + I18n(c, "fail") + ": " + err.Error()
- logger.Warning(msg+I18n(c, "fail")+": ", err)
+ m.Msg = msg + I18nWeb(c, "fail") + ": " + err.Error()
+ logger.Warning(msg+I18nWeb(c, "fail")+": ", err)
}
c.JSON(http.StatusOK, m)
}
diff --git a/web/entity/entity.go b/web/entity/entity.go
index b370b7ba..52f26769 100644
--- a/web/entity/entity.go
+++ b/web/entity/entity.go
@@ -41,6 +41,7 @@ type AllSetting struct {
TgRunTime string `json:"tgRunTime" form:"tgRunTime"`
TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"`
TgCpu int `json:"tgCpu" form:"tgCpu"`
+ TgLang string `json:"tgLang" form:"tgLang"`
XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"`
TimeLocation string `json:"timeLocation" form:"timeLocation"`
SecretEnable bool `json:"secretEnable" form:"secretEnable"`
diff --git a/web/global/hashStorage.go b/web/global/hashStorage.go
new file mode 100644
index 00000000..9dfea169
--- /dev/null
+++ b/web/global/hashStorage.go
@@ -0,0 +1,82 @@
+package global
+
+import (
+ "crypto/md5"
+ "encoding/hex"
+ "regexp"
+ "sync"
+ "time"
+)
+
+type HashEntry struct {
+ Hash string
+ Value string
+ Timestamp time.Time
+}
+
+type HashStorage struct {
+ sync.RWMutex
+ Data map[string]HashEntry
+ Expiration time.Duration
+
+}
+
+func NewHashStorage(expiration time.Duration) *HashStorage {
+ return &HashStorage{
+ Data: make(map[string]HashEntry),
+ Expiration: expiration,
+ }
+}
+
+func (h *HashStorage) SaveHash(query string) string {
+ h.Lock()
+ defer h.Unlock()
+
+ md5Hash := md5.Sum([]byte(query))
+ md5HashString := hex.EncodeToString(md5Hash[:])
+
+ entry := HashEntry{
+ Hash: md5HashString,
+ Value: query,
+ Timestamp: time.Now(),
+ }
+
+ h.Data[md5HashString] = entry
+
+ return md5HashString
+}
+
+
+func (h *HashStorage) GetValue(hash string) (string, bool) {
+ h.RLock()
+ defer h.RUnlock()
+
+ entry, exists := h.Data[hash]
+
+ return entry.Value, exists
+}
+
+func (h *HashStorage) IsMD5(hash string) bool {
+ match, _ := regexp.MatchString("^[a-f0-9]{32}$", hash)
+ return match
+}
+
+func (h *HashStorage) RemoveExpiredHashes() {
+ h.Lock()
+ defer h.Unlock()
+
+ now := time.Now()
+
+ for hash, entry := range h.Data {
+ if now.Sub(entry.Timestamp) > h.Expiration {
+ delete(h.Data, hash)
+ }
+ }
+}
+
+func (h *HashStorage) Reset() {
+ h.Lock()
+ defer h.Unlock()
+
+ h.Data = make(map[string]HashEntry)
+}
diff --git a/web/html/xui/form/tls_settings.html b/web/html/xui/form/tls_settings.html
index 91642727..35f101ca 100644
--- a/web/html/xui/form/tls_settings.html
+++ b/web/html/xui/form/tls_settings.html
@@ -10,7 +10,7 @@
Reality
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.realityDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.realityDesc" }}</span>
</template>
<a-icon type="question-circle" theme="filled"></a-icon>
</a-tooltip>
@@ -22,7 +22,7 @@
XTLS
<a-tooltip>
<template slot="title">
- <span>{{ i18n "pages.inbounds.xtlsDesc" }}</span>
+ <span>{{ i18n "pages.inbounds.xtlsDesc" }}</span>
</template>
<a-icon type="question-circle" theme="filled"></a-icon>
</a-tooltip>
@@ -100,7 +100,7 @@
</a-form>
<!-- xtls settings -->
-<a-form v-if="inbound.xtls" layout="inline">
+<a-form v-else-if="inbound.xtls" layout="inline">
<a-form-item label='{{ i18n "domainName" }}'>
<a-input v-model.trim="inbound.stream.xtls.server"></a-input>
</a-form-item>
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index 6fdf0c43..a66e84a9 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -105,6 +105,10 @@
</a-col>
</a-row>
</div>
+ <a-switch v-model="enableFilter"
+ checked-children='{{ i18n "search" }}' un-checked-children='{{ i18n "filter" }}'
+ @change="toggleFilter" style="margin-right: 10px;">
+ </a-switch>
<a-input v-if="!enableFilter" v-model.lazy="searchKey" placeholder='{{ i18n "search" }}' autofocus style="max-width: 300px"></a-input>
<a-radio-group v-if="enableFilter" v-model="filterBy" @change="filterInbounds" button-style="solid">
<a-radio-button value="">{{ i18n "none" }}</a-radio-button>
@@ -112,10 +116,6 @@
<a-radio-button value="depleted">{{ i18n "depleted" }}</a-radio-button>
<a-radio-button value="expiring">{{ i18n "depletingSoon" }}</a-radio-button>
</a-radio-group>
- <a-switch v-model="enableFilter"
- checked-children='{{ i18n "search" }}' un-checked-children='{{ i18n "filter" }}'
- @change="toggleFilter">
- </a-switch>
<a-table :columns="columns" :row-key="dbInbound => dbInbound.id"
:data-source="searchedInbounds"
:loading="spinning" :scroll="{ x: 1300 }"
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index 3dd1f57b..f5ea4994 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -23,6 +23,34 @@
:not(.ant-card-dark)>.ant-tabs-top-bar {
background: white;
}
+
+ .alert-msg {
+ color: rgb(194, 117, 18);
+ font-weight: bold;
+ font-size: 20px;
+ margin-top: 5px;
+ padding: 16px 6px;
+ text-align: center;
+ border-bottom: 1px solid;
+ }
+
+ .alert-msg > i {
+ color: inherit;
+ font-size: 24px;
+ }
+
+ .collapse-title {
+ color: inherit;
+ font-weight: bold;
+ font-size: 18px;
+ padding: 10px 20px;
+ border-bottom: 2px solid;
+ }
+
+ .collapse-title > i {
+ color: inherit;
+ font-size: 24px;
+ }
</style>
<body>
<a-layout id="app" v-cloak>
@@ -35,8 +63,14 @@
<a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.settings.save" }}</a-button>
<a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.settings.restartPanel" }}</a-button>
</a-space>
- <a-tabs style="margin:1rem 0.5rem;" default-active-key="1" :class="themeSwitcher.darkCardClass" >
+ <a-tabs style="margin:1rem 0.5rem;" default-active-key="1" :class="themeSwitcher.darkCardClass">
<a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="alert-msg">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.infoDesc" }}
+ </h2>
+ </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="number" title='{{ i18n "pages.settings.panelPort"}}' desc='{{ i18n "pages.settings.panelPortDesc"}}' v-model="allSetting.webPort" :min="0"></setting-list-item>
@@ -72,12 +106,6 @@
</a-row>
</a-list-item>
</a-list>
- <a-row :xs="24" :sm="24" :lg="12">
- <h2 style="color: inherit; font-weight: bold; font-size: 16px; padding: 5px 5px; text-align: center;">
- <a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
- {{ i18n "pages.settings.infoDesc" }}
- </h2>
- </a-row>
</a-tab-pane>
<a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings"}}' style="padding: 20px;">
<a-tabs class="ant-card-dark-securitybox-nohover" default-active-key="sec-1" :class="themeSwitcher.darkCardClass">
@@ -144,8 +172,8 @@
</a-space>
<a-divider style="padding: 20px;">{{ i18n "pages.settings.templates.title"}} </a-divider>
<a-row :xs="24" :sm="24" :lg="12">
- <h2 style="color: inherit; font-weight: bold; font-size: 16px; padding: 5px 5px; text-align: center;">
- <a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
+ <h2 class="alert-msg">
+ <a-icon type="warning"></a-icon>
{{ i18n "pages.settings.infoDesc" }}
</h2>
</a-row>
@@ -154,8 +182,8 @@
<a-collapse>
<a-collapse-panel header='{{ i18n "pages.settings.templates.generalConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
- <h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
- <a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
{{ i18n "pages.settings.templates.generalConfigsDesc" }}
</h2>
</a-row>
@@ -199,8 +227,8 @@
</a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.settings.templates.blockConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
- <h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
- <a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
{{ i18n "pages.settings.templates.blockConfigsDesc" }}
</h2>
</a-row>
@@ -212,8 +240,8 @@
</a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.settings.templates.blockCountryConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
- <h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
- <a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
{{ i18n "pages.settings.templates.blockCountryConfigsDesc" }}
</h2>
</a-row>
@@ -226,8 +254,8 @@
</a-collapse-panel>
<a-collapse-panel header='{{ i18n "pages.settings.templates.directCountryConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
- <h2 style="color: inherit; font-weight: bold; font-size: 18px; padding: 10px 20px; border-bottom: 2px solid;">
- <a-icon type="warning" style="color: inherit; font-size: 24px;"></a-icon>
+ <h2 class="collapse-title">