feat: Fix issue where accessing with an unbound domain returns an error (#8014)

This commit is contained in:
zhengkunwang 2025-02-26 17:02:17 +08:00 committed by GitHub
parent d36311cff1
commit 19a3967603
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 143 additions and 32 deletions

View file

@ -68,11 +68,14 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }
if err := settingService.Update(req.Key, req.Value); err != nil { if err := settingService.Update(req.Key, req.Value); err != nil {
helper.InternalServer(c, err) helper.InternalServer(c, err)
return return
} }
if req.Key == "SecurityEntrance" {
entranceValue := base64.StdEncoding.EncodeToString([]byte(req.Value))
c.SetCookie("SecurityEntrance", entranceValue, 0, "", "", false, true)
}
helper.SuccessWithOutData(c) helper.SuccessWithOutData(c)
} }

View file

@ -3,6 +3,8 @@ package router
import ( import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/core/app/repo"
"github.com/1Panel-dev/1Panel/core/utils/common"
"net/http" "net/http"
"regexp" "regexp"
"strconv" "strconv"
@ -61,7 +63,7 @@ func checkEntrance(c *gin.Context) bool {
return string(entranceValue) == entrance return string(entranceValue) == entrance
} }
func handleNoRoute(c *gin.Context) { func handleNoRoute(c *gin.Context, resType string) {
resPage, err := service.NewIAuthService().GetResponsePage() resPage, err := service.NewIAuthService().GetResponsePage()
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, "Internal Server Error") c.String(http.StatusInternalServerError, "Internal Server Error")
@ -73,6 +75,9 @@ func handleNoRoute(c *gin.Context) {
} }
file := fmt.Sprintf("html/%s.html", resPage) 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) data, err := res.ErrorMsg.ReadFile(file)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, "Internal Server Error") c.String(http.StatusInternalServerError, "Internal Server Error")
@ -110,6 +115,43 @@ func checkFrontendPath(c *gin.Context) bool {
return true 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) { func setWebStatic(rootRouter *gin.RouterGroup) {
rootRouter.StaticFS("/public", http.FS(web.Favicon)) rootRouter.StaticFS("/public", http.FS(web.Favicon))
rootRouter.StaticFS("/favicon.ico", 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) { rootRouter.GET("/"+entrance, func(c *gin.Context) {
currentEntrance := authService.GetSecurityEntrance() currentEntrance := authService.GetSecurityEntrance()
if currentEntrance != entrance { if currentEntrance != entrance {
handleNoRoute(c) handleNoRoute(c, "")
return return
} }
toIndexHtml(c) toIndexHtml(c)
}) })
} }
rootRouter.GET("/", func(c *gin.Context) { rootRouter.GET("/", func(c *gin.Context) {
if !checkEntrance(c) { if !checkEntrance(c) && !checkSession(c) {
handleNoRoute(c) handleNoRoute(c, "")
return 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 := http.FileServer(http.FS(web.IndexHtml))
staticServer.ServeHTTP(c.Writer, c.Request) staticServer.ServeHTTP(c.Writer, c.Request)
}) })
@ -173,6 +228,14 @@ func Routers() *gin.Engine {
} }
Router.NoRoute(func(c *gin.Context) { 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) { if checkFrontendPath(c) {
toIndexHtml(c) toIndexHtml(c)
return return
@ -181,7 +244,7 @@ func Routers() *gin.Engine {
toIndexHtml(c) toIndexHtml(c)
return return
} }
handleNoRoute(c) handleNoRoute(c, "")
}) })
return Router return Router

View file

@ -2,12 +2,11 @@ package middleware
import ( import (
"errors" "errors"
"net" "github.com/1Panel-dev/1Panel/core/utils/common"
"strings" "strings"
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper" "github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/core/app/repo" "github.com/1Panel-dev/1Panel/core/app/repo"
"github.com/1Panel-dev/1Panel/core/global"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -29,7 +28,7 @@ func WhiteAllow() gin.HandlerFunc {
if len(ip) == 0 { if len(ip) == 0 {
continue continue
} }
if ip == clientIP || (strings.Contains(ip, "/") && checkIpInCidr(ip, clientIP)) { if ip == clientIP || (strings.Contains(ip, "/") && common.CheckIpInCidr(ip, clientIP)) {
c.Next() c.Next()
return return
} }
@ -41,26 +40,3 @@ func WhiteAllow() gin.HandlerFunc {
helper.ErrorWithDetail(c, 310, "ErrInternalServer", errors.New("IP address not allowed")) 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
}
}
}

View file

@ -163,3 +163,26 @@ func GetLang(c *gin.Context) string {
} }
return lang 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
}
}
}

View file

@ -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"
}

View file

@ -766,3 +766,13 @@ export const encryptPassword = (password: string) => {
const passwordCipher = aesEncrypt(password, aesKey); const passwordCipher = aesEncrypt(password, aesKey);
return `${keyCipher}:${passwordCipher}`; return `${keyCipher}:${passwordCipher}`;
}; };
export async function loadJson(lang: string): Promise<Object> {
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}`);
}
}