fix(agent-server): authenticate /v1/nodes via session tokens
This commit is contained in:
parent
cc0ff117f6
commit
fbe04d37b1
12
api/api.go
12
api/api.go
@ -301,14 +301,14 @@ func RegisterRoutes(r *gin.Engine, opts ...Option) {
|
||||
}
|
||||
registerAdminRoutes(apiGroup, h)
|
||||
|
||||
// Canonical user-facing agent routes under /api/agent-server/v1.
|
||||
// Keep this in the authenticated user API group so dashboard requests can
|
||||
// read registered nodes directly without console-side custom route logic.
|
||||
agentServerGroup := apiGroup.Group("/agent-server/v1")
|
||||
// Canonical user-facing agent routes.
|
||||
// These endpoints use session-based auth in handler logic and intentionally
|
||||
// stay outside token middleware to support dashboard session tokens.
|
||||
agentServerGroup := r.Group("/api/agent-server/v1")
|
||||
agentServerGroup.GET("/nodes", h.listAgentNodes)
|
||||
|
||||
// User agent routes - /api/agent/nodes
|
||||
agentGroup := apiGroup.Group("/agent")
|
||||
// Legacy alias kept for backward compatibility.
|
||||
agentGroup := r.Group("/api/agent")
|
||||
agentGroup.GET("/nodes", h.listAgentNodes)
|
||||
}
|
||||
|
||||
|
||||
@ -44,20 +44,8 @@ type vlessNode struct {
|
||||
}
|
||||
|
||||
func (h *handler) listAgentNodes(c *gin.Context) {
|
||||
// Get current user ID to use as VLESS UUID
|
||||
userID := auth.GetUserID(c)
|
||||
if userID == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.store.GetUserByID(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrUserNotFound) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "user_not_found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch user"})
|
||||
user, ok := h.resolveAgentNodeUser(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@ -148,6 +136,53 @@ func (h *handler) listAgentNodes(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, nodes)
|
||||
}
|
||||
|
||||
func (h *handler) resolveAgentNodeUser(c *gin.Context) (*store.User, bool) {
|
||||
if userID := strings.TrimSpace(auth.GetUserID(c)); userID != "" && userID != "system" {
|
||||
user, err := h.store.GetUserByID(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrUserNotFound) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "user_not_found"})
|
||||
return nil, false
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed_to_fetch_user"})
|
||||
return nil, false
|
||||
}
|
||||
return user, true
|
||||
}
|
||||
|
||||
token := extractToken(c.GetHeader("Authorization"))
|
||||
if token == "" {
|
||||
token = strings.TrimSpace(c.Query("token"))
|
||||
}
|
||||
if token == "" {
|
||||
if cookie, err := c.Cookie(sessionCookieName); err == nil {
|
||||
token = strings.TrimSpace(cookie)
|
||||
}
|
||||
}
|
||||
if token == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "session_token_required", "message": "session token is required"})
|
||||
return nil, false
|
||||
}
|
||||
|
||||
sess, ok := h.lookupSession(token)
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid_session", "message": "session token is invalid or expired"})
|
||||
return nil, false
|
||||
}
|
||||
|
||||
user, err := h.store.GetUserByID(c.Request.Context(), sess.userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrUserNotFound) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "user_not_found"})
|
||||
return nil, false
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed_to_fetch_user"})
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return user, true
|
||||
}
|
||||
|
||||
func parseProxyNodeHosts(publicURL string, extraHosts []string) []string {
|
||||
seen := make(map[string]struct{})
|
||||
hosts := make([]string, 0)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user