mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-09 07:00:48 +08:00
feat(system): add session check for agent api (#8258)
This commit is contained in:
parent
732bbd8951
commit
220b6223a3
11 changed files with 356 additions and 278 deletions
|
@ -2,10 +2,16 @@ package router
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/res"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/security"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
|
@ -38,6 +44,13 @@ func Proxy() gin.HandlerFunc {
|
|||
currentNode = c.Request.Header.Get("CurrentNode")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api/v2/") && !checkSession(c) {
|
||||
data, _ := res.ErrorMsg.ReadFile("html/401.html")
|
||||
c.Data(401, "text/html; charset=utf-8", data)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(c.Request.URL.Path, "/api/v2/core") && (currentNode == "local" || len(currentNode) == 0 || currentNode == "127.0.0.1") {
|
||||
sockPath := "/etc/1panel/agent.sock"
|
||||
if _, err := os.Stat(sockPath); err != nil {
|
||||
|
@ -58,6 +71,13 @@ func Proxy() gin.HandlerFunc {
|
|||
req.URL.Host = "unix"
|
||||
},
|
||||
Transport: transport,
|
||||
ModifyResponse: func(response *http.Response) error {
|
||||
if response.StatusCode == 404 {
|
||||
security.HandleNotSecurity(c, "")
|
||||
c.Abort()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
proxy.ServeHTTP(c.Writer, c.Request)
|
||||
c.Abort()
|
||||
|
@ -67,3 +87,22 @@ func Proxy() gin.HandlerFunc {
|
|||
c.Abort()
|
||||
}
|
||||
}
|
||||
|
||||
func checkSession(c *gin.Context) bool {
|
||||
psession, err := global.SESSION.Get(c)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
setting, err := settingRepo.Get(repo.WithByKey("SessionTimeout"))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
lifeTime, _ := strconv.Atoi(setting.Value)
|
||||
httpsSetting, err := settingRepo.Get(repo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_ = global.SESSION.Set(c, psession, httpsSetting.Value == constant.StatusEnable, lifeTime)
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -3,157 +3,26 @@ package router
|
|||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/service"
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/res"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/docs"
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/web"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/i18n"
|
||||
"github.com/1Panel-dev/1Panel/core/middleware"
|
||||
rou "github.com/1Panel-dev/1Panel/core/router"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/security"
|
||||
"github.com/gin-contrib/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerfiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
var (
|
||||
Router *gin.Engine
|
||||
)
|
||||
|
||||
func toIndexHtml(c *gin.Context) {
|
||||
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
_, _ = c.Writer.Write(web.IndexByte)
|
||||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
func isEntrancePath(c *gin.Context) bool {
|
||||
entrance := service.NewIAuthService().GetSecurityEntrance()
|
||||
if entrance != "" && strings.TrimSuffix(c.Request.URL.Path, "/") == "/"+entrance {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkEntrance(c *gin.Context) bool {
|
||||
authService := service.NewIAuthService()
|
||||
entrance := authService.GetSecurityEntrance()
|
||||
if entrance == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
cookieValue, err := c.Cookie("SecurityEntrance")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
entranceValue, err := base64.StdEncoding.DecodeString(cookieValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return string(entranceValue) == entrance
|
||||
}
|
||||
|
||||
func handleNoRoute(c *gin.Context, resType string) {
|
||||
resPage, err := service.NewIAuthService().GetResponsePage()
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
if resPage == "444" {
|
||||
c.String(444, "")
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
return
|
||||
}
|
||||
statusCode, err := strconv.Atoi(resPage)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
c.Data(statusCode, "text/html; charset=utf-8", data)
|
||||
}
|
||||
|
||||
func isFrontendPath(c *gin.Context) bool {
|
||||
reqUri := strings.TrimSuffix(c.Request.URL.Path, "/")
|
||||
if _, ok := constant.WebUrlMap[reqUri]; ok {
|
||||
return true
|
||||
}
|
||||
for _, route := range constant.DynamicRoutes {
|
||||
if match, _ := regexp.MatchString(route, reqUri); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkFrontendPath(c *gin.Context) bool {
|
||||
if !isFrontendPath(c) {
|
||||
return false
|
||||
}
|
||||
authService := service.NewIAuthService()
|
||||
if authService.GetSecurityEntrance() != "" {
|
||||
return authService.IsLogin(c)
|
||||
}
|
||||
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))
|
||||
|
@ -172,23 +41,14 @@ func setWebStatic(rootRouter *gin.RouterGroup) {
|
|||
rootRouter.GET("/"+entrance, func(c *gin.Context) {
|
||||
currentEntrance := authService.GetSecurityEntrance()
|
||||
if currentEntrance != entrance {
|
||||
handleNoRoute(c, "")
|
||||
security.HandleNotSecurity(c, "")
|
||||
return
|
||||
}
|
||||
toIndexHtml(c)
|
||||
security.ToIndexHtml(c)
|
||||
})
|
||||
}
|
||||
rootRouter.GET("/", func(c *gin.Context) {
|
||||
if !checkEntrance(c) && !checkSession(c) {
|
||||
handleNoRoute(c, "")
|
||||
return
|
||||
}
|
||||
if !checkBindDomain(c) {
|
||||
handleNoRoute(c, "err_domain")
|
||||
return
|
||||
}
|
||||
if !checkIPLimit(c) {
|
||||
handleNoRoute(c, "err_ip_limit")
|
||||
if !security.CheckSecurity(c) {
|
||||
return
|
||||
}
|
||||
entrance = authService.GetSecurityEntrance()
|
||||
|
@ -229,26 +89,13 @@ func Routers() *gin.Engine {
|
|||
router.InitRouter(PrivateGroup)
|
||||
}
|
||||
|
||||
Router.Use(middleware.SessionAuth())
|
||||
Router.Use(middleware.ApiAuth())
|
||||
Router.Use(Proxy())
|
||||
Router.NoRoute(func(c *gin.Context) {
|
||||
if !checkBindDomain(c) {
|
||||
handleNoRoute(c, "err_domain")
|
||||
if !security.HandleNotRoute(c) {
|
||||
return
|
||||
}
|
||||
if !checkIPLimit(c) {
|
||||
handleNoRoute(c, "err_ip_limit")
|
||||
return
|
||||
}
|
||||
if checkFrontendPath(c) {
|
||||
toIndexHtml(c)
|
||||
return
|
||||
}
|
||||
if isEntrancePath(c) {
|
||||
toIndexHtml(c)
|
||||
return
|
||||
}
|
||||
handleNoRoute(c, "")
|
||||
security.HandleNotSecurity(c, "")
|
||||
})
|
||||
|
||||
return Router
|
||||
|
|
117
core/middleware/api_auth.go
Normal file
117
core/middleware/api_auth.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ApiAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api/v2/core/auth") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
panelToken := c.GetHeader("1Panel-Token")
|
||||
panelTimestamp := c.GetHeader("1Panel-Timestamp")
|
||||
if panelToken != "" || panelTimestamp != "" {
|
||||
if global.Api.ApiInterfaceStatus == constant.StatusEnable {
|
||||
clientIP := c.ClientIP()
|
||||
if !isValid1PanelTimestamp(panelTimestamp) {
|
||||
helper.BadAuth(c, "ErrApiConfigKeyTimeInvalid", nil)
|
||||
return
|
||||
}
|
||||
if !isValid1PanelToken(panelToken, panelTimestamp) {
|
||||
helper.BadAuth(c, "ErrApiConfigKeyInvalid", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if !isIPInWhiteList(clientIP) {
|
||||
helper.BadAuth(c, "ErrApiConfigIPInvalid", nil)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
return
|
||||
} else {
|
||||
helper.BadAuth(c, "ErrApiConfigStatusInvalid", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isValid1PanelTimestamp(panelTimestamp string) bool {
|
||||
apiKeyValidityTime := global.Api.ApiKeyValidityTime
|
||||
apiTime, err := strconv.Atoi(apiKeyValidityTime)
|
||||
if err != nil || apiTime < 0 {
|
||||
global.LOG.Errorf("apiTime %d, err: %v", apiTime, err)
|
||||
return false
|
||||
}
|
||||
if apiTime == 0 {
|
||||
return true
|
||||
}
|
||||
panelTime, err := strconv.ParseInt(panelTimestamp, 10, 64)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("panelTimestamp %s, panelTime %d, apiTime %d, err: %v", panelTimestamp, apiTime, panelTime, err)
|
||||
return false
|
||||
}
|
||||
nowTime := time.Now().Unix()
|
||||
tolerance := int64(60)
|
||||
if panelTime > nowTime+tolerance {
|
||||
global.LOG.Errorf("Valid Panel Timestamp, apiTime %d, panelTime %d, nowTime %d, err: %v", apiTime, panelTime, nowTime, err)
|
||||
return false
|
||||
}
|
||||
return nowTime-panelTime <= int64(apiTime)*60+tolerance
|
||||
}
|
||||
|
||||
func isValid1PanelToken(panelToken string, panelTimestamp string) bool {
|
||||
system1PanelToken := global.Api.ApiKey
|
||||
return panelToken == GenerateMD5("1panel"+system1PanelToken+panelTimestamp)
|
||||
}
|
||||
|
||||
func isIPInWhiteList(clientIP string) bool {
|
||||
ipWhiteString := global.Api.IpWhiteList
|
||||
if len(ipWhiteString) == 0 {
|
||||
global.LOG.Error("IP whitelist is empty")
|
||||
return false
|
||||
}
|
||||
ipWhiteList, ipErr := common.HandleIPList(ipWhiteString)
|
||||
if ipErr != nil {
|
||||
global.LOG.Errorf("Failed to handle IP list: %v", ipErr)
|
||||
return false
|
||||
}
|
||||
clientParsedIP := net.ParseIP(clientIP)
|
||||
if clientParsedIP == nil {
|
||||
return false
|
||||
}
|
||||
iPv4 := clientParsedIP.To4()
|
||||
iPv6 := clientParsedIP.To16()
|
||||
for _, cidr := range ipWhiteList {
|
||||
if (iPv4 != nil && (cidr == "0.0.0.0" || cidr == "0.0.0.0/0" || iPv4.String() == cidr)) || (iPv6 != nil && (cidr == "::/0" || iPv6.String() == cidr)) {
|
||||
return true
|
||||
}
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if (iPv4 != nil && ipNet.Contains(iPv4)) || (iPv6 != nil && ipNet.Contains(iPv6)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GenerateMD5(param string) string {
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(param))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
|
@ -1,19 +1,13 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SessionAuth() gin.HandlerFunc {
|
||||
|
@ -23,32 +17,6 @@ func SessionAuth() gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
panelToken := c.GetHeader("1Panel-Token")
|
||||
panelTimestamp := c.GetHeader("1Panel-Timestamp")
|
||||
if panelToken != "" || panelTimestamp != "" {
|
||||
if global.Api.ApiInterfaceStatus == constant.StatusEnable {
|
||||
clientIP := c.ClientIP()
|
||||
if !isValid1PanelTimestamp(panelTimestamp) {
|
||||
helper.BadAuth(c, "ErrApiConfigKeyTimeInvalid", nil)
|
||||
return
|
||||
}
|
||||
if !isValid1PanelToken(panelToken, panelTimestamp) {
|
||||
helper.BadAuth(c, "ErrApiConfigKeyInvalid", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if !isIPInWhiteList(clientIP) {
|
||||
helper.BadAuth(c, "ErrApiConfigIPInvalid", nil)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
return
|
||||
} else {
|
||||
helper.BadAuth(c, "ErrApiConfigStatusInvalid", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
psession, err := global.SESSION.Get(c)
|
||||
if err != nil {
|
||||
helper.BadAuth(c, "ErrNotLogin", err)
|
||||
|
@ -70,70 +38,3 @@ func SessionAuth() gin.HandlerFunc {
|
|||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func isValid1PanelTimestamp(panelTimestamp string) bool {
|
||||
apiKeyValidityTime := global.Api.ApiKeyValidityTime
|
||||
apiTime, err := strconv.Atoi(apiKeyValidityTime)
|
||||
if err != nil || apiTime < 0 {
|
||||
global.LOG.Errorf("apiTime %d, err: %v", apiTime, err)
|
||||
return false
|
||||
}
|
||||
if apiTime == 0 {
|
||||
return true
|
||||
}
|
||||
panelTime, err := strconv.ParseInt(panelTimestamp, 10, 64)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("panelTimestamp %s, panelTime %d, apiTime %d, err: %v", panelTimestamp, apiTime, panelTime, err)
|
||||
return false
|
||||
}
|
||||
nowTime := time.Now().Unix()
|
||||
tolerance := int64(60)
|
||||
if panelTime > nowTime+tolerance {
|
||||
global.LOG.Errorf("Valid Panel Timestamp, apiTime %d, panelTime %d, nowTime %d, err: %v", apiTime, panelTime, nowTime, err)
|
||||
return false
|
||||
}
|
||||
return nowTime-panelTime <= int64(apiTime)*60+tolerance
|
||||
}
|
||||
|
||||
func isValid1PanelToken(panelToken string, panelTimestamp string) bool {
|
||||
system1PanelToken := global.Api.ApiKey
|
||||
return panelToken == GenerateMD5("1panel"+system1PanelToken+panelTimestamp)
|
||||
}
|
||||
|
||||
func isIPInWhiteList(clientIP string) bool {
|
||||
ipWhiteString := global.Api.IpWhiteList
|
||||
if len(ipWhiteString) == 0 {
|
||||
global.LOG.Error("IP whitelist is empty")
|
||||
return false
|
||||
}
|
||||
ipWhiteList, ipErr := common.HandleIPList(ipWhiteString)
|
||||
if ipErr != nil {
|
||||
global.LOG.Errorf("Failed to handle IP list: %v", ipErr)
|
||||
return false
|
||||
}
|
||||
clientParsedIP := net.ParseIP(clientIP)
|
||||
if clientParsedIP == nil {
|
||||
return false
|
||||
}
|
||||
iPv4 := clientParsedIP.To4()
|
||||
iPv6 := clientParsedIP.To16()
|
||||
for _, cidr := range ipWhiteList {
|
||||
if (iPv4 != nil && (cidr == "0.0.0.0" || cidr == "0.0.0.0/0" || iPv4.String() == cidr)) || (iPv6 != nil && (cidr == "::/0" || iPv6.String() == cidr)) {
|
||||
return true
|
||||
}
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if (iPv4 != nil && ipNet.Contains(iPv4)) || (iPv6 != nil && ipNet.Contains(iPv6)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GenerateMD5(param string) string {
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(param))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
|
|
176
core/utils/security/security.go
Normal file
176
core/utils/security/security.go
Normal file
|
@ -0,0 +1,176 @@
|
|||
package security
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/app/service"
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/res"
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/web"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func HandleNotRoute(c *gin.Context) bool {
|
||||
if !checkBindDomain(c) {
|
||||
HandleNotSecurity(c, "err_domain")
|
||||
return false
|
||||
}
|
||||
if !checkIPLimit(c) {
|
||||
HandleNotSecurity(c, "err_ip_limit")
|
||||
return false
|
||||
}
|
||||
if checkFrontendPath(c) {
|
||||
ToIndexHtml(c)
|
||||
return false
|
||||
}
|
||||
if isEntrancePath(c) {
|
||||
ToIndexHtml(c)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func CheckSecurity(c *gin.Context) bool {
|
||||
if !checkEntrance(c) && !checkSession(c) {
|
||||
HandleNotSecurity(c, "")
|
||||
return false
|
||||
}
|
||||
if !checkBindDomain(c) {
|
||||
HandleNotSecurity(c, "err_domain")
|
||||
return false
|
||||
}
|
||||
if !checkIPLimit(c) {
|
||||
HandleNotSecurity(c, "err_ip_limit")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ToIndexHtml(c *gin.Context) {
|
||||
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
c.Writer.WriteHeader(http.StatusOK)
|
||||
_, _ = c.Writer.Write(web.IndexByte)
|
||||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
func isEntrancePath(c *gin.Context) bool {
|
||||
entrance := service.NewIAuthService().GetSecurityEntrance()
|
||||
if entrance != "" && strings.TrimSuffix(c.Request.URL.Path, "/") == "/"+entrance {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkEntrance(c *gin.Context) bool {
|
||||
authService := service.NewIAuthService()
|
||||
entrance := authService.GetSecurityEntrance()
|
||||
if entrance == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
cookieValue, err := c.Cookie("SecurityEntrance")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
entranceValue, err := base64.StdEncoding.DecodeString(cookieValue)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return string(entranceValue) == entrance
|
||||
}
|
||||
|
||||
func HandleNotSecurity(c *gin.Context, resType string) {
|
||||
resPage, err := service.NewIAuthService().GetResponsePage()
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
if resPage == "444" {
|
||||
c.String(444, "")
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
return
|
||||
}
|
||||
statusCode, err := strconv.Atoi(resPage)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
c.Data(statusCode, "text/html; charset=utf-8", data)
|
||||
}
|
||||
|
||||
func isFrontendPath(c *gin.Context) bool {
|
||||
reqUri := strings.TrimSuffix(c.Request.URL.Path, "/")
|
||||
if _, ok := constant.WebUrlMap[reqUri]; ok {
|
||||
return true
|
||||
}
|
||||
for _, route := range constant.DynamicRoutes {
|
||||
if match, _ := regexp.MatchString(route, reqUri); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkFrontendPath(c *gin.Context) bool {
|
||||
if !isFrontendPath(c) {
|
||||
return false
|
||||
}
|
||||
authService := service.NewIAuthService()
|
||||
if authService.GetSecurityEntrance() != "" {
|
||||
return authService.IsLogin(c)
|
||||
}
|
||||
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
|
||||
}
|
|
@ -44,6 +44,7 @@ const config = reactive({
|
|||
});
|
||||
const open = ref(false);
|
||||
const showTail = ref(true);
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const openWithTaskID = (id: string, tail: boolean) => {
|
||||
config.taskID = id;
|
||||
|
@ -65,7 +66,7 @@ const openWithResourceID = (taskType: string, taskOperate: string, resourceID: n
|
|||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
bus.emit('close', true);
|
||||
emit('close', true);
|
||||
bus.emit('refreshTask', true);
|
||||
};
|
||||
|
||||
|
|
|
@ -42,13 +42,14 @@ router.beforeEach((to, from, next) => {
|
|||
if (to.path === '/apps/all' && to.query.install != undefined) {
|
||||
return next();
|
||||
}
|
||||
const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || '');
|
||||
if (to.query.uncached != undefined) {
|
||||
const query = { ...to.query };
|
||||
delete query.uncached;
|
||||
localStorage.removeItem(activeMenuKey);
|
||||
return next({ path: to.path, query });
|
||||
}
|
||||
|
||||
const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || '');
|
||||
const cachedRoute = localStorage.getItem(activeMenuKey);
|
||||
if (
|
||||
to.meta.activeMenu &&
|
||||
|
|
|
@ -185,7 +185,7 @@ import Install from '../detail/install/index.vue';
|
|||
import router from '@/routers';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { newUUID } from '@/utils/util';
|
||||
import { newUUID, jumpToPath } from '@/utils/util';
|
||||
import Detail from '../detail/index.vue';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
@ -254,7 +254,7 @@ const openInstall = (app: App.App) => {
|
|||
case 'go':
|
||||
case 'python':
|
||||
case 'dotnet':
|
||||
router.push({ path: '/websites/runtimes/' + app.type });
|
||||
jumpToPath(router, '/websites/runtimes/' + app.type);
|
||||
break;
|
||||
default:
|
||||
const params = {
|
||||
|
|
|
@ -72,7 +72,7 @@ import { ref } from 'vue';
|
|||
import Install from './install/index.vue';
|
||||
import router from '@/routers';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { computeSizeFromMB } from '@/utils/util';
|
||||
import { computeSizeFromMB, jumpToPath } from '@/utils/util';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -133,16 +133,12 @@ const toLink = (link: string) => {
|
|||
const openInstall = () => {
|
||||
switch (app.value.type) {
|
||||
case 'php':
|
||||
router.push({ path: '/websites/runtimes/php' });
|
||||
break;
|
||||
case 'node':
|
||||
router.push({ path: '/websites/runtimes/node' });
|
||||
break;
|
||||
case 'java':
|
||||
router.push({ path: '/websites/runtimes/java' });
|
||||
break;
|
||||
case 'go':
|
||||
router.push({ path: '/websites/runtimes/go' });
|
||||
case 'python':
|
||||
case 'dotnet':
|
||||
jumpToPath(router, '/websites/runtimes/' + app.value.type);
|
||||
break;
|
||||
default:
|
||||
const params = {
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<el-form @submit.prevent ref="paramForm" :model="paramModel" label-position="top" :rules="rules">
|
||||
<div v-for="(p, index) in params" :key="index">
|
||||
<el-form-item
|
||||
:prop="p.key"
|
||||
:prop="'params.' + p.key"
|
||||
:label="getLabel(p)"
|
||||
v-if="p.showValue == undefined || p.showValue == ''"
|
||||
>
|
||||
|
@ -57,7 +57,7 @@
|
|||
</el-select>
|
||||
<el-input v-else v-model.trim="paramModel.params[p.key]" :disabled="!p.edit"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :prop="p.key" :label="getLabel(p)" v-else>
|
||||
<el-form-item :prop="'params.' + p.key" :label="getLabel(p)" v-else>
|
||||
<el-input v-model.trim="p.showValue" :disabled="!p.edit"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
|
|
@ -354,7 +354,7 @@
|
|||
</div>
|
||||
</template>
|
||||
</LayoutContent>
|
||||
<Backups ref="backupRef" @close="search" />
|
||||
<Backups ref="backupRef" />
|
||||
<Uploads ref="uploadRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<AppDelete ref="deleteRef" @close="search" />
|
||||
|
|
Loading…
Add table
Reference in a new issue