diff --git a/core/middleware/demo_handle.go b/core/middleware/demo_handle.go index 431bc2b2c..e418221c8 100644 --- a/core/middleware/demo_handle.go +++ b/core/middleware/demo_handle.go @@ -9,64 +9,117 @@ import ( "github.com/gin-gonic/gin" ) -var whiteUrlList = map[string]struct{}{ - "/api/v2/dashboard/app/launcher/option": {}, - "/api/v2/websites/config": {}, - "/api/v2/websites/waf/config": {}, - "/api/v2/files/size": {}, - "/api/v2/runtimes/sync": {}, - "/api/v2/toolbox/device/base": {}, - "/api/v2/files/user/group": {}, - "/api/v2/files/mount": {}, - "/api/v2/hosts/ssh/log": {}, - "/api/v2/toolbox/clam/base": {}, - "/api/v2/backups/record/size": {}, +type demoRoute struct { + method string + path string +} - "/api/v2/core/auth/login": {}, - "/api/v2/core/logs/login": {}, - "/api/v2/core/logs/operation": {}, - "/api/v2/core/auth/logout": {}, +var demoAllowedRoutes = map[demoRoute]struct{}{ + {http.MethodPost, "/api/v2/dashboard/app/launcher/option"}: {}, + {http.MethodPost, "/api/v2/websites/config"}: {}, + {http.MethodPost, "/api/v2/files/size"}: {}, + {http.MethodPost, "/api/v2/files/ai-search"}: {}, + {http.MethodPost, "/api/v2/runtimes/sync"}: {}, + {http.MethodPost, "/api/v2/toolbox/device/base"}: {}, + {http.MethodPost, "/api/v2/files/user/group"}: {}, + {http.MethodPost, "/api/v2/files/mount"}: {}, + {http.MethodPost, "/api/v2/hosts/ssh/log"}: {}, + {http.MethodPost, "/api/v2/toolbox/clam/base"}: {}, + {http.MethodPost, "/api/v2/backups/record/size"}: {}, - "/api/v2/apps/installed/loadport": {}, - "/api/v2/apps/installed/check": {}, - "/api/v2/apps/installed/conninfo": {}, - "/api/v2/databases/load/file": {}, - "/api/v2/databases/variables": {}, - "/api/v2/databases/status": {}, - "/api/v2/databases/baseinfo": {}, + {http.MethodPost, "/api/v2/core/auth/login"}: {}, + {http.MethodPost, "/api/v2/core/logs/login"}: {}, + {http.MethodPost, "/api/v2/core/logs/operation"}: {}, + {http.MethodPost, "/api/v2/core/auth/logout"}: {}, - "/api/v2/xpack/waf/attack/stat": {}, - "/api/v2/xpack/waf/config/website": {}, - "/api/v2/xpack/waf/relation/stat": {}, + {http.MethodPost, "/api/v2/apps/installed/loadport"}: {}, + {http.MethodPost, "/api/v2/apps/installed/check"}: {}, + {http.MethodPost, "/api/v2/apps/installed/conninfo"}: {}, + {http.MethodPost, "/api/v2/databases/common/info"}: {}, + {http.MethodPost, "/api/v2/databases/common/load/file"}: {}, + {http.MethodPost, "/api/v2/databases/variables"}: {}, + {http.MethodPost, "/api/v2/databases/status"}: {}, - "/api/v2/xpack/monitor/stat": {}, - "/api/v2/xpack/monitor/visitors": {}, - "/api/v2/xpack/monitor/visitors/loc": {}, - "/api/v2/xpack/monitor/qps": {}, - "/api/v2/xpack/monitor/logs/stat": {}, - "/api/v2/xpack/monitor/websites": {}, - "/api/v2/xpack/monitor/trend": {}, - "/api/v2/xpack/monitor/rank": {}, - "/api/v2/xpack/waf/cdn": {}, + {http.MethodPost, "/api/v2/ai/accounts/counts"}: {}, + {http.MethodPost, "/api/v2/ai/accounts/models"}: {}, + {http.MethodPost, "/api/v2/ai/agents/overview"}: {}, + {http.MethodPost, "/api/v2/ai/agents/hermes/chat/sessions"}: {}, + {http.MethodPost, "/api/v2/ai/agents/agent/list"}: {}, + {http.MethodPost, "/api/v2/ai/agents/agent/channels"}: {}, + {http.MethodPost, "/api/v2/ai/agents/agent/md/list"}: {}, + {http.MethodPost, "/api/v2/ai/agents/plugins/list"}: {}, + {http.MethodPost, "/api/v2/ai/agents/skills/list"}: {}, + {http.MethodPost, "/api/v2/alert/cronjob/list"}: {}, + {http.MethodPost, "/api/v2/xpack/cluster/replica/status"}: {}, + {http.MethodPost, "/api/v2/xpack/cluster/ipport/healthy"}: {}, + {http.MethodPost, "/api/v2/xpack/tampers/template/list"}: {}, + {http.MethodPost, "/api/v2/xpack/vllm/command-template/list"}: {}, + {http.MethodPost, "/api/v2/core/enterprise/skills-hub/published"}: {}, + {http.MethodPost, "/api/v2/core/enterprise/skills-hub/versions"}: {}, + {http.MethodPost, "/api/v2/core/enterprise/ai-proxy/smart-route/statistics"}: {}, + {http.MethodPost, "/api/v2/core/enterprise/ai-proxy/usage/attempts"}: {}, + {http.MethodPost, "/api/v2/core/enterprise/ai-proxy/usage/statistics"}: {}, - "/api/v2/core/nodes/list": {}, + {http.MethodPost, "/api/v2/xpack/waf/attack/stat"}: {}, + {http.MethodPost, "/api/v2/xpack/waf/config/website"}: {}, + {http.MethodPost, "/api/v2/xpack/waf/relation/stat"}: {}, + + {http.MethodPost, "/api/v2/xpack/monitor/stat"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/visitors"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/visitors/loc"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/qps"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/logs/stat"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/websites"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/trend"}: {}, + {http.MethodPost, "/api/v2/xpack/monitor/rank"}: {}, + {http.MethodPost, "/api/v2/xpack/waf/cdn"}: {}, + + {http.MethodPost, "/api/v2/core/nodes/list"}: {}, +} + +var demoDeniedRoutes = map[demoRoute]struct{}{ + {http.MethodGet, "/api/v2/containers/exec"}: {}, + {http.MethodGet, "/api/v2/hosts/terminal/local"}: {}, + {http.MethodGet, "/api/v2/hosts/terminal/ssh"}: {}, + {http.MethodGet, "/api/v2/hosts/terminal/container"}: {}, + {http.MethodGet, "/api/v2/core/enterprise/vms/console/ws"}: {}, } func DemoHandle() gin.HandlerFunc { return func(c *gin.Context) { - if strings.Contains(c.Request.URL.Path, "search") || (c.Request.Method == http.MethodGet && c.Request.URL.Path != "/api/v2/containers/exec") { - c.Next() - return - } - if _, ok := whiteUrlList[c.Request.URL.Path]; ok { + if isDemoRequestAllowed(c.Request.Method, c.Request.URL.Path) { c.Next() return } - c.JSON(http.StatusInternalServerError, dto.Response{ - Code: http.StatusInternalServerError, + c.JSON(http.StatusForbidden, dto.Response{ + Code: http.StatusForbidden, Message: buserr.New("ErrDemoEnvironment").Error(), }) c.Abort() } } + +func isDemoRequestAllowed(method, path string) bool { + route := demoRoute{method: method, path: path} + if _, denied := demoDeniedRoutes[route]; denied { + return false + } + if method == http.MethodGet { + return true + } + if method == http.MethodPost && hasPathSegment(path, "search") { + return true + } + _, allowed := demoAllowedRoutes[route] + return allowed +} + +func hasPathSegment(path, segment string) bool { + for _, item := range strings.Split(strings.Trim(path, "/"), "/") { + if item == segment { + return true + } + } + return false +}