From a2d8c98b0df39216787d2c77af6e499857510e9e Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:13:46 +0430 Subject: create and move middlewares to seperate folder --- web/middleware/domainValidator.go | 21 +++++++++++++++++++++ web/middleware/redirect.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 web/middleware/domainValidator.go create mode 100644 web/middleware/redirect.go (limited to 'web') diff --git a/web/middleware/domainValidator.go b/web/middleware/domainValidator.go new file mode 100644 index 00000000..3adb0f0f --- /dev/null +++ b/web/middleware/domainValidator.go @@ -0,0 +1,21 @@ +package middleware + +import ( + "net/http" + "strings" + + "github.com/gin-gonic/gin" +) + +func DomainValidatorMiddleware(domain string) gin.HandlerFunc { + return func(c *gin.Context) { + host := strings.Split(c.Request.Host, ":")[0] + + if host != domain { + c.AbortWithStatus(http.StatusForbidden) + return + } + + c.Next() + } +} diff --git a/web/middleware/redirect.go b/web/middleware/redirect.go new file mode 100644 index 00000000..e3dc8ada --- /dev/null +++ b/web/middleware/redirect.go @@ -0,0 +1,34 @@ +package middleware + +import ( + "net/http" + "strings" + + "github.com/gin-gonic/gin" +) + +func RedirectMiddleware(basePath string) gin.HandlerFunc { + return func(c *gin.Context) { + // Redirect from old '/xui' path to '/panel' + redirects := map[string]string{ + "panel/API": "panel/api", + "xui/API": "panel/api", + "xui": "panel", + } + + path := c.Request.URL.Path + for from, to := range redirects { + from, to = basePath+from, basePath+to + + if strings.HasPrefix(path, from) { + newPath := to + path[len(from):] + + c.Redirect(http.StatusMovedPermanently, newPath) + c.Abort() + return + } + } + + c.Next() + } +} -- cgit v1.2.3 From 8170b65db4d38002f81825ea876dd3e4c9292931 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:21:14 +0430 Subject: add an option for webDomain --- web/assets/js/model/models.js | 3 ++- web/controller/inbound.go | 2 ++ web/entity/entity.go | 1 + web/global/hashStorage.go | 2 -- web/html/xui/settings.html | 3 ++- web/service/inbound.go | 1 + web/service/setting.go | 7 ++++++- 7 files changed, 14 insertions(+), 5 deletions(-) (limited to 'web') 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/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/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/xui/settings.html b/web/html/xui/settings.html index d78533a1..e7d865f6 100644 --- a/web/html/xui/settings.html +++ b/web/html/xui/settings.html @@ -91,6 +91,7 @@ + @@ -391,9 +392,9 @@ + - diff --git a/web/service/inbound.go b/web/service/inbound.go index 6a182fcf..11522ad2 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -1185,6 +1185,7 @@ func (s *InboundService) GetInboundClientIps(clientEmail string) (string, error) } return InboundClientIps.Ips, nil } + func (s *InboundService) ClearClientIps(clientEmail string) error { db := database.GetDB() diff --git a/web/service/setting.go b/web/service/setting.go index 593b23be..677ccbb2 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -24,6 +24,7 @@ var xrayTemplateConfig string var defaultValueMap = map[string]string{ "xrayTemplateConfig": xrayTemplateConfig, "webListen": "", + "webDomain": "", "webPort": "2053", "webCertFile": "", "webKeyFile": "", @@ -44,7 +45,7 @@ var defaultValueMap = map[string]string{ "subEnable": "false", "subListen": "", "subPort": "2096", - "subPath": "sub/", + "subPath": "/sub/", "subDomain": "", "subCertFile": "", "subKeyFile": "", @@ -225,6 +226,10 @@ func (s *SettingService) GetListen() (string, error) { return s.getString("webListen") } +func (s *SettingService) GetWebDomain() (string, error) { + return s.getString("webDomain") +} + func (s *SettingService) GetTgBotToken() (string, error) { return s.getString("tgBotToken") } -- cgit v1.2.3 From ea7fe09c27da8c12e38f581fd7a4b336b4e55ad7 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:24:18 +0430 Subject: use the middlewares --- web/web.go | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) (limited to 'web') diff --git a/web/web.go b/web/web.go index 543ecf8e..3d8f0242 100644 --- a/web/web.go +++ b/web/web.go @@ -19,6 +19,7 @@ import ( "x-ui/web/controller" "x-ui/web/job" "x-ui/web/locale" + "x-ui/web/middleware" "x-ui/web/network" "x-ui/web/service" @@ -144,28 +145,6 @@ func (s *Server) getHtmlTemplate(funcMap template.FuncMap) (*template.Template, return t, nil } -func redirectMiddleware(basePath string) gin.HandlerFunc { - return func(c *gin.Context) { - // Redirect from old '/xui' path to '/panel' - path := c.Request.URL.Path - redirects := map[string]string{ - "panel/API": "panel/api", - "xui/API": "panel/api", - "xui": "panel", - } - for from, to := range redirects { - from, to = basePath+from, basePath+to - if strings.HasPrefix(path, from) { - newPath := to + path[len(from):] - c.Redirect(http.StatusMovedPermanently, newPath) - c.Abort() - return - } - } - c.Next() - } -} - func (s *Server) initRouter() (*gin.Engine, error) { if config.IsDebug() { gin.SetMode(gin.DebugMode) @@ -177,6 +156,15 @@ func (s *Server) initRouter() (*gin.Engine, error) { engine := gin.Default() + webDomain, err := s.settingService.GetWebDomain() + if err != nil { + return nil, err + } + + if webDomain != "" { + engine.Use(middleware.DomainValidatorMiddleware(webDomain)) + } + secret, err := s.settingService.GetSecret() if err != nil { return nil, err @@ -233,7 +221,7 @@ func (s *Server) initRouter() (*gin.Engine, error) { } // Apply the redirect middleware (`/xui` to `/panel`) - engine.Use(redirectMiddleware(basePath)) + engine.Use(middleware.RedirectMiddleware(basePath)) g := engine.Group(basePath) -- cgit v1.2.3 From c9461f1647f5c36f74f292208f7af105976e5c2b Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:26:29 +0430 Subject: Update translations --- web/translation/translate.en_US.toml | 2 ++ web/translation/translate.fa_IR.toml | 2 ++ web/translation/translate.ru_RU.toml | 2 ++ web/translation/translate.zh_Hans.toml | 2 ++ 4 files changed, 8 insertions(+) (limited to 'web') diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index a15bf44c..edd4ca80 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -221,6 +221,8 @@ "TGBotSettings" = "Telegram Bot Settings" "panelListeningIP" = "Panel Listening IP" "panelListeningIPDesc" = "Leave blank by default to monitor all IPs." +"panelListeningDomain" = "Panel Listening Domain" +"panelListeningDomainDesc" = "Leave blank by default to monitor all domains and IPs" "panelPort" = "Panel Port" "panelPortDesc" = "The port used to display this panel" "publicKeyPath" = "Panel Certificate Public Key File Path" diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index abaa989b..b8b1b5fb 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -221,6 +221,8 @@ "TGBotSettings" = "تنظیمات ربات تلگرام" "panelListeningIP" = "محدودیت آی پی پنل" "panelListeningIPDesc" = "برای استفاده از تمام آی‌پیها به طور پیش فرض خالی بگذارید" +"panelListeningDomain" = "محدودیت دامین پنل" +"panelListeningDomainDesc" = "برای استفاده از تمام دامنه‌ها و آی‌پی‌ها به طور پیش فرض خالی بگذارید" "panelPort" = "پورت پنل" "panelPortDesc" = "پورت مورد استفاده برای نمایش این پنل" "publicKeyPath" = "مسیر فایل گواهی کلید عمومی پنل" diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index 3f0a18e6..a96cad1c 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -221,6 +221,8 @@ "TGBotSettings" = "Настройки Telegram бота" "panelListeningIP" = "IP адрес панели" "panelListeningIPDesc" = "Оставьте пустым для подключения с любого IP" +"panelListeningDomain" = "Домен прослушивания панели" +"panelListeningDomainDesc" = "По умолчанию оставьте пустым, чтобы отслеживать все домены и IP-адреса" "panelPort" = "Порт панели" "panelPortDesc" = "Порт, используемый для отображения этой панели" "publicKeyPath" = "Путь к файлу публичного ключа сертификата панели" diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml index 60f42abc..febbe4b8 100644 --- a/web/translation/translate.zh_Hans.toml +++ b/web/translation/translate.zh_Hans.toml @@ -221,6 +221,8 @@ "TGBotSettings" = "TG提醒相关设置" "panelListeningIP" = "面板监听 IP" "panelListeningIPDesc" = "默认留空监听所有 IP" +"panelListeningDomain" = "面板监听域名" +"panelListeningDomainDesc" = "默认情况下留空以监视所有域名和 IP 地址" "panelPort" = "面板监听端口" "panelPortDesc" = "重启面板生效" "publicKeyPath" = "面板证书公钥文件路径" -- cgit v1.2.3 From fe963d91ef6c4ddb9e56709f993e8cc09f9786c4 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:31:56 +0430 Subject: some improvements --- web/controller/setting.go | 97 +++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 66 deletions(-) (limited to 'web') diff --git a/web/controller/setting.go b/web/controller/setting.go index 0292c46a..306563a2 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"].(string) != "" || result["subCertFile"].(string) != "" { 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) } -- cgit v1.2.3 From 6c26e40aea8f63b2f422c4f9fbf92c7ff1c0383c Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:33:45 +0430 Subject: fix qrModal.client is null --- web/html/common/qrcode_modal.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web') diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index e6b7b998..57bf810d 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -94,7 +94,7 @@ } }, updated() { - if (qrModal.client.subId){ + if (qrModal.client && qrModal.client.subId){ qrModal.subId = qrModal.client.subId; this.setQrCode("qrCode-sub",this.genSubLink(qrModal.subId)); } -- cgit v1.2.3 From 1c9fc9422e304c8710b56e9719960e429e7a1878 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:34:15 +0430 Subject: add buildURL func --- web/assets/js/util/common.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'web') 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}`; +} -- cgit v1.2.3 From b203067dfd416bd45d34cc2dbaad85ab51fcb085 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:47:07 +0430 Subject: fix urls + use the new buildURL func --- web/html/common/qrcode_modal.html | 30 +++++++++++++----------------- web/html/xui/inbound_info_modal.html | 8 ++------ web/html/xui/inbound_modal.html | 2 +- web/html/xui/inbounds.html | 2 +- web/html/xui/settings.html | 12 +++++------- 5 files changed, 22 insertions(+), 32 deletions(-) (limited to 'web') diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 57bf810d..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 && 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 e7d865f6..e4103c52 100644 --- a/web/html/xui/settings.html +++ b/web/html/xui/settings.html @@ -523,7 +523,7 @@ this.loading(false); if (msg.success) { this.user = {}; - window.location.replace(basePath + "logout") + window.location.replace(basePath + "logout"); } }, async restartPanel() { @@ -542,12 +542,10 @@ if (msg.success) { this.loading(true); await PromiseUtil.sleep(5000); - let protocol = "http://"; - if (this.allSetting.webCertFile !== "") { - protocol = "https://"; - } - const { host } = window.location; - window.location.replace(protocol + host + this.allSetting.webBasePath + "panel/settings"); + const { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.allSetting; + const isTLS = webCertFile !== "" || webKeyFile !== ""; + const url = buildURL({ host, port, isTLS, base, path: "panel/settings" }); + window.location.replace(url); } }, async fetchUserSecret() { -- cgit v1.2.3 From ef7b979d53ba502a5354dd0cfb457e6c1febe125 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 01:49:23 +0430 Subject: move manual list to new tab --- web/html/xui/settings.html | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) (limited to 'web') diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html index e4103c52..745959a2 100644 --- a/web/html/xui/settings.html +++ b/web/html/xui/settings.html @@ -307,23 +307,37 @@ - - -

- - {{ i18n "pages.settings.templates.manualListsDesc" }} -

-
- - - - - - + + + + +

+ + {{ i18n "pages.settings.templates.manualListsDesc" }} +

+
+ + + + + + + + + + + + + + + + + +
- + @@ -336,7 +350,7 @@ - + -- cgit v1.2.3 From 6ae80fc992924bb00dcea9a1a032f1bca3af4b30 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 02:31:00 +0430 Subject: add /id command to tgbot to get user id --- web/service/tgbot.go | 33 +++++++++++++++++++++++---------- web/translation/translate.en_US.toml | 5 +++-- web/translation/translate.fa_IR.toml | 5 +++-- web/translation/translate.ru_RU.toml | 5 +++-- web/translation/translate.zh_Hans.toml | 5 +++-- 5 files changed, 35 insertions(+), 18 deletions(-) (limited to 'web') diff --git a/web/service/tgbot.go b/web/service/tgbot.go index e0261775..0ad7c3c6 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -188,7 +188,7 @@ func (t *Tgbot) OnReceive() { } func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) { - msg := "" + msg, onlyMessage := "", false command, commandArgs := tu.ParseCommand(message.Text) @@ -204,8 +204,13 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo } msg += "\n\n" + t.I18nBot("tgbot.commands.pleaseChoose") case "status": + onlyMessage = true msg += t.I18nBot("tgbot.commands.status") + case "id": + onlyMessage = true + msg += t.I18nBot("tgbot.commands.getID", "ID=="+strconv.FormatInt(message.From.ID, 10)) case "usage": + onlyMessage = true if len(commandArgs) > 0 { if isAdmin { t.searchClient(chatId, commandArgs[0]) @@ -216,6 +221,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo msg += t.I18nBot("tgbot.commands.usage") } case "inbound": + onlyMessage = true if isAdmin && len(commandArgs) > 0 { t.searchInbound(chatId, commandArgs[0]) } else { @@ -224,6 +230,11 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo default: msg += t.I18nBot("tgbot.commands.unknown") } + + if onlyMessage { + t.SendMsgToTgbot(chatId, msg) + return + } t.SendAnswer(chatId, msg, isAdmin) } @@ -498,6 +509,7 @@ func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.R if !isRunning { return } + if msg == "" { logger.Info("[tgbot] message is empty!") return @@ -723,7 +735,7 @@ func (t *Tgbot) getClientUsage(chatId int64, tgUserName string, tgUserID string) output := "" output += t.I18nBot("tgbot.messages.email", "Email=="+traffic.Email) - if (traffic.Enable) { + if traffic.Enable { output += t.I18nBot("tgbot.messages.active") if flag { output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime) @@ -791,6 +803,7 @@ func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ... output := "" output += t.I18nBot("tgbot.messages.email", "Email=="+email) output += t.I18nBot("tgbot.messages.TGUser", "TelegramID=="+tgId) + output += t.I18nBot("tgbot.messages.refreshedOn", "Time=="+time.Now().Format("2006-01-02 15:04:05")) inlineKeyboard := tu.InlineKeyboard( tu.InlineKeyboardRow( @@ -840,7 +853,7 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { flag := false diff := traffic.ExpiryTime/1000 - now if traffic.ExpiryTime == 0 { - expiryTime = t.I18nBot("tgbot.unlimited") + expiryTime = t.I18nBot("tgbot.unlimited") } else if diff > 172800 || !traffic.Enable { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } else if traffic.ExpiryTime < 0 { @@ -860,7 +873,7 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { output := "" output += t.I18nBot("tgbot.messages.email", "Email=="+traffic.Email) - if (traffic.Enable) { + if traffic.Enable { output += t.I18nBot("tgbot.messages.active") if flag { output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime) @@ -918,7 +931,7 @@ func (t *Tgbot) searchInbound(chatId int64, remark string) { t.SendMsgToTgbot(chatId, msg) return } - + now := time.Now().Unix() for _, inbound := range inbouds { info := "" @@ -958,7 +971,7 @@ func (t *Tgbot) searchInbound(chatId int64, remark string) { output := "" output += t.I18nBot("tgbot.messages.email", "Email=="+traffic.Email) - if (traffic.Enable) { + if traffic.Enable { output += t.I18nBot("tgbot.messages.active") if flag { output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime) @@ -998,7 +1011,7 @@ func (t *Tgbot) searchForClient(chatId int64, query string) { flag := false diff := traffic.ExpiryTime/1000 - now if traffic.ExpiryTime == 0 { - expiryTime = t.I18nBot("tgbot.unlimited") + expiryTime = t.I18nBot("tgbot.unlimited") } else if diff > 172800 || !traffic.Enable { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } else if traffic.ExpiryTime < 0 { @@ -1018,7 +1031,7 @@ func (t *Tgbot) searchForClient(chatId int64, query string) { output := "" output += t.I18nBot("tgbot.messages.email", "Email=="+traffic.Email) - if (traffic.Enable) { + if traffic.Enable { output += t.I18nBot("tgbot.messages.active") if flag { output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime) @@ -1117,7 +1130,7 @@ func (t *Tgbot) getExhausted() string { for _, traffic := range exhaustedClients { expiryTime := "" flag := false - diff := (traffic.ExpiryTime - now)/1000 + diff := (traffic.ExpiryTime - now) / 1000 if traffic.ExpiryTime == 0 { expiryTime = t.I18nBot("tgbot.unlimited") } else if diff > 172800 || !traffic.Enable { @@ -1138,7 +1151,7 @@ func (t *Tgbot) getExhausted() string { } output += t.I18nBot("tgbot.messages.email", "Email=="+traffic.Email) - if (traffic.Enable) { + if traffic.Enable { output += t.I18nBot("tgbot.messages.active") if flag { output += t.I18nBot("tgbot.messages.expireIn", "Time=="+expiryTime) diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index edd4ca80..401a1265 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -168,7 +168,7 @@ "setDefaultCert" = "Set cert from panel" "xtlsDesc" = "Xray core needs to be 1.7.5" "realityDesc" = "Xray core needs to be 1.8.0 or higher." -"telegramDesc" = "use Telegram ID without @ or chat IDs ( you can get it here @userinfobot )" +"telegramDesc" = "use Telegram ID without @ or chat IDs ( you can get it here @userinfobot or use '/id' command in bot )" "subscriptionDesc" = "you can find your sub link on Details, also you can use the same name for several configurations" [pages.client] @@ -240,7 +240,7 @@ "telegramToken" = "Telegram Token" "telegramTokenDesc" = "You must get the token from the manager of Telegram bots @botfather" "telegramChatId" = "Telegram Admin Chat IDs" -"telegramChatIdDesc" = "Multiple Chat IDs separated by comma. use @userinfobot to get your Chat IDs." +"telegramChatIdDesc" = "Multiple Chat IDs separated by comma. use @userinfobot or use '/id' command in bot to get your Chat IDs." "telegramNotifyTime" = "Telegram bot notification time" "telegramNotifyTimeDesc" = "Use Crontab timing format." "tgNotifyBackup" = "Database Backup" @@ -399,6 +399,7 @@ "welcome" = "🤖 Welcome to {{ .Hostname }} management bot.\r\n" "status" = "✅ Bot is ok!" "usage" = "❗ Please provide a text to search!" +"getID" = "🆔 Your ID: {{ .ID }}" "helpAdminCommands" = "Search for a client email:\r\n/usage [Email]\r\n \r\nSearch for inbounds (with client stats):\r\n/inbound [Remark]" "helpClientCommands" = "To search for statistics, just use folowing command:\r\n \r\n/usage [UUID|Password]\r\n \r\nUse UUID for vmess/vless and Password for Trojan." diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index b8b1b5fb..841483c7 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -168,7 +168,7 @@ "setDefaultCert" = "استفاده از گواهی پنل" "xtlsDesc" = "هسته Xray باید 1.7.5 باشد" "realityDesc" = "هسته Xray باید 1.8.0 و بالاتر باشد" -"telegramDesc" = "از آیدی تلگرام بدون @ یا آیدی چت استفاده کنید (می توانید آن را از اینجا دریافت کنید @userinfobot)" +"telegramDesc" = "از آیدی تلگرام بدون @ یا آیدی چت استفاده کنید (می توانید آن را از اینجا دریافت کنید @userinfobot یا در ربات دستور '/id' را وارد کنید)" "subscriptionDesc" = "می توانید ساب لینک خود را در جزئیات پیدا کنید، همچنین می توانید از همین نام برای چندین کانفیگ استفاده کنید" [pages.client] @@ -240,7 +240,7 @@ "telegramToken" = "توکن تلگرام" "telegramTokenDesc" = "توکن را باید از مدیر بات های تلگرام دریافت کنید @botfather" "telegramChatId" = "آی دی تلگرام مدیریت" -"telegramChatIdDesc" = "از @userinfobot برای دریافت شناسه های چت خود استفاده کنید. با استفاده از کاما میتونید چند آی دی را از هم جدا کنید. " +"telegramChatIdDesc" = "از @userinfobot یا دستور '/id' در ربات برای دریافت شناسه های چت خود استفاده کنید. با استفاده از کاما میتونید چند آی دی را از هم جدا کنید. " "telegramNotifyTime" = "مدت زمان نوتیفیکیشن ربات تلگرام" "telegramNotifyTimeDesc" = "از فرمت زمان بندی لینوکس استفاده کنید " "tgNotifyBackup" = "پشتیبان گیری از پایگاه داده" @@ -399,6 +399,7 @@ "welcome" = "🤖 به ربات مدیریت {{ .Hostname }} خوش آمدید.\r\n" "status" = "✅ ربات در حالت عادی است!" "usage" = "❗ لطفاً یک متن برای جستجو وارد کنید!" +"getID" = "🆔 شناسه شما: {{ .ID }}" "helpAdminCommands" = "برای جستجوی ایمیل مشتری:\r\n/usage [ایمیل]\r\n \r\nبرای جستجوی ورودی‌ها (با آمار مشتری):\r\n/inbound [توضیح]" "helpClientCommands" = "برای جستجوی آمار، فقط از دستور زیر استفاده کنید:\r\n \r\n/usage [UUID|رمز عبور]\r\n \r\nاز UUID برای vmess/vless و از رمز عبور برای Trojan استفاده کنید." diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index a96cad1c..45a73a97 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -168,7 +168,7 @@ "setDefaultCert" = "Установить сертификат с панели" "xtlsDesc" = "Версия Xray должна быть не ниже 1.7.5" "realityDesc" = "Версия Xray должна быть не ниже 1.8.0" -"telegramDesc" = "Используйте Telegram ID без @ или ID пользователя (вы можете получить его у @userinfobot)" +"telegramDesc" = "Используйте идентификатор Telegram без символа @ или идентификатора чата (можно получить его здесь @userinfobot или использовать команду '/id' в боте)" "subscriptionDesc" = "Вы можете найти свою ссылку подписки в разделе «Подробнее», также вы можете использовать одно и то же имя для нескольких конфигураций" [pages.client] @@ -240,7 +240,7 @@ "telegramToken" = "Токен Telegram бота" "telegramTokenDesc" = "Необходимо получить токен у менеджера ботов Telegram @botfather" "telegramChatId" = "Telegram ID админа бота" -"telegramChatIdDesc" = "Несколько Telegram ID, разделённых запятой. Используйте @userinfobot, чтобы получить Telegram ID" +"telegramChatIdDesc" = "Множественные идентификаторы чата, разделенные запятыми. Чтобы получить свои идентификаторы чатов, используйте @userinfobot или команду '/id' в боте." "telegramNotifyTime" = "Частота уведомлений бота Telegram" "telegramNotifyTimeDesc" = "Используйте формат времени Crontab" "tgNotifyBackup" = "Резервное копирование базы данных" @@ -399,6 +399,7 @@ "welcome" = "🤖 Добро пожаловать в бота управления {{ .Hostname }}.\r\n" "status" = "✅ Бот работает нормально!" "usage" = "❗ Пожалуйста, укажите текст для поиска!" +"getID" = "🆔 Ваш ID: {{ .ID }}" "helpAdminCommands" = "Поиск по электронной почте клиента:\r\n/usage [Email]\r\n \r\nПоиск входящих соединений (со статистикой клиента):\r\n/inbound [Remark]" "helpClientCommands" = "Для получения статистики используйте следующую команду:\r\n \r\n/usage [UUID|Password]\r\n \r\nИспользуйте UUID для vmess/vless и пароль для Trojan." diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml index febbe4b8..70c24df7 100644 --- a/web/translation/translate.zh_Hans.toml +++ b/web/translation/translate.zh_Hans.toml @@ -168,7 +168,7 @@ "setDefaultCert" = "从面板设置证书" "xtlsDesc" = "Xray核心需要1.7.5" "realityDesc" = "Xray核心需要1.8.0及以上版本" -"telegramDesc" = "使用不带@的电报 ID 或聊天 ID(您可以在此处获取 @userinfobot)" +"telegramDesc" = "使用 Telegram ID,不包含 @ 符号或聊天 ID(可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)" "subscriptionDesc" = "您可以在详细信息上找到您的子链接,也可以对多个配置使用相同的名称" [pages.client] @@ -240,7 +240,7 @@ "telegramToken" = "电报机器人TOKEN" "telegramTokenDesc" = "重启面板生效" "telegramChatId" = "以逗号分隔的多个 chatID 重启面板生效" -"telegramChatIdDesc" = "多个聊天 ID 以逗号分隔。使用@userinfobot 获取您的聊天 ID。重新启动面板以应用更改。" +"telegramChatIdDesc" = "多个聊天 ID 用逗号分隔。使用 @userinfobot 或在机器人中使用'/id'命令获取您的聊天 ID。" "telegramNotifyTime" = "电报机器人通知时间" "telegramNotifyTimeDesc" = "采用Crontab定时格式,重启面板生效" "tgNotifyBackup" = "数据库备份" @@ -399,6 +399,7 @@ "welcome" = "🤖 欢迎来到{{ .Hostname }}管理机器人。\r\n" "status" = "✅ 机器人正常运行!" "usage" = "❗ 请输入要搜索的文本!" +"getID" = "🆔 您的ID为:{{ .ID }}" "helpAdminCommands" = "搜索客户端邮箱:\r\n/usage [Email]\r\n \r\n搜索入站连接(包含客户端统计信息):\r\n/inbound [Remark]" "helpClientCommands" = "要搜索统计信息,请使用以下命令:\r\n \r\n/usage [UUID|Password]\r\n \r\n对于vmess/vless,请使用UUID;对于Trojan,请使用密码。" -- cgit v1.2.3 From c565a429afd8f3fb1a9aa40c8db696090b91fd54 Mon Sep 17 00:00:00 2001 From: Hamidreza Ghavami <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 03:29:59 +0430 Subject: fix setting --- web/controller/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web') diff --git a/web/controller/setting.go b/web/controller/setting.go index 306563a2..cd509293 100644 --- a/web/controller/setting.go +++ b/web/controller/setting.go @@ -93,7 +93,7 @@ func (a *SettingController) getDefaultSettings(c *gin.Context) { } subTLS := false - if result["subKeyFile"].(string) != "" || result["subCertFile"].(string) != "" { + if result["subKeyFile"] != "" || result["subCertFile"] != "" { subTLS = true } result["subTLS"] = subTLS -- cgit v1.2.3 From d694e6eafccad246c63264714897316f671d6428 Mon Sep 17 00:00:00 2001 From: Hamidreza <70919649+hamid-gh98@users.noreply.github.com> Date: Wed, 31 May 2023 05:01:20 +0330 Subject: FIX tgbot adminIds --- web/service/tgbot.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'web') diff --git a/web/service/tgbot.go b/web/service/tgbot.go index 0ad7c3c6..d1a1e3fe 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -77,13 +77,15 @@ func (t *Tgbot) Start(i18nFS embed.FS) error { return err } - for _, adminId := range strings.Split(tgBotid, ",") { - id, err := strconv.Atoi(adminId) - if err != nil { - logger.Warning("Failed to get IDs from GetTgBotChatId:", err) - return err + if tgBotid != "" { + for _, adminId := range strings.Split(tgBotid, ",") { + id, err := strconv.Atoi(adminId) + if err != nil { + logger.Warning("Failed to get IDs from GetTgBotChatId:", err) + return err + } + adminIds = append(adminIds, int64(id)) } - adminIds = append(adminIds, int64(id)) } bot, err = telego.NewBot(tgBottoken) -- cgit v1.2.3