From 19a39676030a7934434e5ac67b555b0da09fc32a Mon Sep 17 00:00:00 2001 From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:02:17 +0800 Subject: [PATCH] feat: Fix issue where accessing with an unbound domain returns an error (#8014) --- core/app/api/v2/setting.go | 5 +- core/init/router/router.go | 73 +++++++++++++++++-- core/middleware/ip_limit.go | 28 +------ core/utils/common/common.go | 23 ++++++ frontend/src/assets/json/china/en.json | 36 +++++++++ .../json/{china-name.json => china/zh.json} | 0 frontend/src/utils/util.ts | 10 +++ 7 files changed, 143 insertions(+), 32 deletions(-) create mode 100644 frontend/src/assets/json/china/en.json rename frontend/src/assets/json/{china-name.json => china/zh.json} (100%) diff --git a/core/app/api/v2/setting.go b/core/app/api/v2/setting.go index 8d9818791..b71f2daf4 100644 --- a/core/app/api/v2/setting.go +++ b/core/app/api/v2/setting.go @@ -68,11 +68,14 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) { if err := helper.CheckBindAndValidate(&req, c); err != nil { return } - if err := settingService.Update(req.Key, req.Value); err != nil { helper.InternalServer(c, err) return } + if req.Key == "SecurityEntrance" { + entranceValue := base64.StdEncoding.EncodeToString([]byte(req.Value)) + c.SetCookie("SecurityEntrance", entranceValue, 0, "", "", false, true) + } helper.SuccessWithOutData(c) } diff --git a/core/init/router/router.go b/core/init/router/router.go index 22e6568dc..a7d0cfd59 100644 --- a/core/init/router/router.go +++ b/core/init/router/router.go @@ -3,6 +3,8 @@ package router import ( "encoding/base64" "fmt" + "github.com/1Panel-dev/1Panel/core/app/repo" + "github.com/1Panel-dev/1Panel/core/utils/common" "net/http" "regexp" "strconv" @@ -61,7 +63,7 @@ func checkEntrance(c *gin.Context) bool { return string(entranceValue) == entrance } -func handleNoRoute(c *gin.Context) { +func handleNoRoute(c *gin.Context, resType string) { resPage, err := service.NewIAuthService().GetResponsePage() if err != nil { c.String(http.StatusInternalServerError, "Internal Server Error") @@ -73,6 +75,9 @@ func handleNoRoute(c *gin.Context) { } file := fmt.Sprintf("html/%s.html", resPage) + if resPage == "200" && resType != "" { + file = fmt.Sprintf("html/200_%s.html", resType) + } data, err := res.ErrorMsg.ReadFile(file) if err != nil { c.String(http.StatusInternalServerError, "Internal Server Error") @@ -110,6 +115,43 @@ func checkFrontendPath(c *gin.Context) bool { return true } +func checkBindDomain(c *gin.Context) bool { + settingRepo := repo.NewISettingRepo() + status, _ := settingRepo.Get(repo.WithByKey("BindDomain")) + if len(status.Value) == 0 { + return true + } + domains := c.Request.Host + parts := strings.Split(c.Request.Host, ":") + if len(parts) > 0 { + domains = parts[0] + } + return domains == status.Value +} + +func checkIPLimit(c *gin.Context) bool { + settingRepo := repo.NewISettingRepo() + status, _ := settingRepo.Get(repo.WithByKey("AllowIPs")) + if len(status.Value) == 0 { + return true + } + clientIP := c.ClientIP() + for _, ip := range strings.Split(status.Value, ",") { + if len(ip) == 0 { + continue + } + if ip == clientIP || (strings.Contains(ip, "/") && common.CheckIpInCidr(ip, clientIP)) { + return true + } + } + return false +} + +func checkSession(c *gin.Context) bool { + _, err := global.SESSION.Get(c) + return err == nil +} + func setWebStatic(rootRouter *gin.RouterGroup) { rootRouter.StaticFS("/public", http.FS(web.Favicon)) rootRouter.StaticFS("/favicon.ico", http.FS(web.Favicon)) @@ -128,17 +170,30 @@ func setWebStatic(rootRouter *gin.RouterGroup) { rootRouter.GET("/"+entrance, func(c *gin.Context) { currentEntrance := authService.GetSecurityEntrance() if currentEntrance != entrance { - handleNoRoute(c) + handleNoRoute(c, "") return } toIndexHtml(c) }) } rootRouter.GET("/", func(c *gin.Context) { - if !checkEntrance(c) { - handleNoRoute(c) + if !checkEntrance(c) && !checkSession(c) { + handleNoRoute(c, "") return } + if !checkBindDomain(c) { + handleNoRoute(c, "err_domain") + return + } + if !checkIPLimit(c) { + handleNoRoute(c, "err_ip_limit") + return + } + entrance = authService.GetSecurityEntrance() + if entrance != "" { + entranceValue := base64.StdEncoding.EncodeToString([]byte(entrance)) + c.SetCookie("SecurityEntrance", entranceValue, 0, "", "", false, true) + } staticServer := http.FileServer(http.FS(web.IndexHtml)) staticServer.ServeHTTP(c.Writer, c.Request) }) @@ -173,6 +228,14 @@ func Routers() *gin.Engine { } Router.NoRoute(func(c *gin.Context) { + if !checkBindDomain(c) { + handleNoRoute(c, "err_domain") + return + } + if !checkIPLimit(c) { + handleNoRoute(c, "err_ip_limit") + return + } if checkFrontendPath(c) { toIndexHtml(c) return @@ -181,7 +244,7 @@ func Routers() *gin.Engine { toIndexHtml(c) return } - handleNoRoute(c) + handleNoRoute(c, "") }) return Router diff --git a/core/middleware/ip_limit.go b/core/middleware/ip_limit.go index c829fb627..880d6c709 100644 --- a/core/middleware/ip_limit.go +++ b/core/middleware/ip_limit.go @@ -2,12 +2,11 @@ package middleware import ( "errors" - "net" + "github.com/1Panel-dev/1Panel/core/utils/common" "strings" "github.com/1Panel-dev/1Panel/core/app/api/v2/helper" "github.com/1Panel-dev/1Panel/core/app/repo" - "github.com/1Panel-dev/1Panel/core/global" "github.com/gin-gonic/gin" ) @@ -29,7 +28,7 @@ func WhiteAllow() gin.HandlerFunc { if len(ip) == 0 { continue } - if ip == clientIP || (strings.Contains(ip, "/") && checkIpInCidr(ip, clientIP)) { + if ip == clientIP || (strings.Contains(ip, "/") && common.CheckIpInCidr(ip, clientIP)) { c.Next() return } @@ -41,26 +40,3 @@ func WhiteAllow() gin.HandlerFunc { helper.ErrorWithDetail(c, 310, "ErrInternalServer", errors.New("IP address not allowed")) } } - -func checkIpInCidr(cidr, checkIP string) bool { - ip, ipNet, err := net.ParseCIDR(cidr) - if err != nil { - global.LOG.Errorf("parse CIDR %s failed, err: %v", cidr, err) - return false - } - for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); incIP(ip) { - if ip.String() == checkIP { - return true - } - } - return false -} - -func incIP(ip net.IP) { - for j := len(ip) - 1; j >= 0; j-- { - ip[j]++ - if ip[j] > 0 { - break - } - } -} diff --git a/core/utils/common/common.go b/core/utils/common/common.go index b255d9688..f45fbe4e2 100644 --- a/core/utils/common/common.go +++ b/core/utils/common/common.go @@ -163,3 +163,26 @@ func GetLang(c *gin.Context) string { } return lang } + +func CheckIpInCidr(cidr, checkIP string) bool { + ip, ipNet, err := net.ParseCIDR(cidr) + if err != nil { + global.LOG.Errorf("parse CIDR %s failed, err: %v", cidr, err) + return false + } + for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); incIP(ip) { + if ip.String() == checkIP { + return true + } + } + return false +} + +func incIP(ip net.IP) { + for j := len(ip) - 1; j >= 0; j-- { + ip[j]++ + if ip[j] > 0 { + break + } + } +} diff --git a/frontend/src/assets/json/china/en.json b/frontend/src/assets/json/china/en.json new file mode 100644 index 000000000..20627cdfd --- /dev/null +++ b/frontend/src/assets/json/china/en.json @@ -0,0 +1,36 @@ +{ + "Anhui": "Anhui", + "Beijing": "Beijing", + "Fujian": "Fujian", + "Gansu": "Gansu", + "Guangdong": "Guangdong", + "Guangxi": "Guangxi", + "Guizhou": "Guizhou", + "Hainan": "Hainan", + "Hebei": "Hebei", + "Henan": "Henan", + "Heilongjiang": "Heilongjiang", + "Hubei": "Hubei", + "Hunan": "Hunan", + "Jilin": "Jilin", + "Jiangsu": "Jiangsu", + "Jiangxi": "Jiangxi", + "Liaoning": "Liaoning", + "Inner Mongolia": "Inner Mongolia", + "Ningxia": "Ningxia", + "Qinghai": "Qinghai", + "Shandong": "Shandong", + "Shanxi": "Shanxi", + "Shaanxi": "Shaanxi", + "Shanghai": "Shanghai", + "Sichuan": "Sichuan", + "Tianjin": "Tianjin", + "Tibet": "Tibet", + "Xinjiang": "Xinjiang", + "Yunnan": "Yunnan", + "Zhejiang": "Zhejiang", + "Chongqing": "Chongqing", + "HongKong": "Hong Kong", + "Macao": "Macau", + "Taiwan": "Taiwan" +} diff --git a/frontend/src/assets/json/china-name.json b/frontend/src/assets/json/china/zh.json similarity index 100% rename from frontend/src/assets/json/china-name.json rename to frontend/src/assets/json/china/zh.json diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 0bff13ebb..5546a70be 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -766,3 +766,13 @@ export const encryptPassword = (password: string) => { const passwordCipher = aesEncrypt(password, aesKey); return `${keyCipher}:${passwordCipher}`; }; + +export async function loadJson(lang: string): Promise { + try { + lang = lang == 'zh' ? 'zh' : 'en'; + const jsonModule = await import(`@/assets/json/china/${lang}.json`); + return jsonModule.default; + } catch (error) { + throw new Error(`Language file not found: ${lang}`); + } +}