fix(api/proxmox): add websocket validation to journalctl and tail endpoints

Add required websocket check at the beginning of both journalctl and tail endpoint handlers to ensure these endpoints only accept websocket connections.
This commit is contained in:
yusing
2026-02-22 19:54:09 +08:00
parent 2305eca90b
commit 4e5ded13fb
2 changed files with 20 additions and 4 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yusing/godoxy/internal/proxmox"
"github.com/yusing/goutils/apitypes"
"github.com/yusing/goutils/http/httpheaders"
"github.com/yusing/goutils/http/websocket"
)
@@ -15,10 +16,10 @@ import (
// e.g. ws://localhost:8889/api/v1/proxmox/journalctl/pve/127?service=pveproxy&service=pvedaemon&limit=10
type JournalctlRequest struct {
Node string `form:"node" uri:"node" binding:"required"` // Node name
VMID *int `form:"vmid" uri:"vmid"` // Container VMID (optional - if not provided, streams node journalctl)
Services []string `form:"service" uri:"service"` // Service names
Limit *int `form:"limit" uri:"limit" default:"100" binding:"min=1,max=1000"` // Limit output lines (1-1000)
Node string `form:"node" uri:"node" binding:"required"` // Node name
VMID *int `form:"vmid" uri:"vmid"` // Container VMID (optional - if not provided, streams node journalctl)
Services []string `form:"service" uri:"service"` // Service names
Limit *int `form:"limit" uri:"limit" default:"100" binding:"omitempty,min=1,max=1000"` // Limit output lines (1-1000)
} // @name ProxmoxJournalctlRequest
// @x-id "journalctl"
@@ -40,6 +41,11 @@ type JournalctlRequest struct {
// @Router /proxmox/journalctl/{node}/{vmid} [get]
// @Router /proxmox/journalctl/{node}/{vmid}/{service} [get]
func Journalctl(c *gin.Context) {
if !httpheaders.IsWebsocket(c.Request.Header) {
c.JSON(http.StatusBadRequest, apitypes.Error("websocket required"))
return
}
var request JournalctlRequest
uriErr := c.ShouldBindUri(&request)
queryErr := c.ShouldBindQuery(&request)
@@ -48,6 +54,10 @@ func Journalctl(c *gin.Context) {
return
}
if request.Limit == nil {
request.Limit = new(100)
}
node, ok := proxmox.Nodes.Get(request.Node)
if !ok {
c.JSON(http.StatusNotFound, apitypes.Error("node not found"))

View File

@@ -7,6 +7,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yusing/godoxy/internal/proxmox"
"github.com/yusing/goutils/apitypes"
"github.com/yusing/goutils/http/httpheaders"
"github.com/yusing/goutils/http/websocket"
)
@@ -34,6 +35,11 @@ type TailRequest struct {
// @Failure 500 {object} apitypes.ErrorResponse "Internal server error"
// @Router /proxmox/tail [get]
func Tail(c *gin.Context) {
if !httpheaders.IsWebsocket(c.Request.Header) {
c.JSON(http.StatusBadRequest, apitypes.Error("websocket required"))
return
}
var request TailRequest
if err := c.ShouldBindQuery(&request); err != nil {
c.JSON(http.StatusBadRequest, apitypes.Error("invalid request", err))