mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
GHSA-vrmh-5mmx-hjwx: GET /api/v1/server/:id/service and GET /api/v1/service/:id/history both iterate the raw service list and emit ServiceName / timing for any service that happens to monitor the queried server, ignoring the owner's EnableShowInService=false flag. Both routes are on optionalAuth, so unauthenticated visitors could enumerate hidden services by name and timing. Introduce userCanViewService(c, service): - EnableShowInService=true -> always visible - admin -> always visible - authenticated owner -> visible (HasPermission) - everyone else -> hidden getServiceHistory rejects unknown-or-invisible service with the same 'service not found' message so the endpoint cannot be used as an oracle. listServerServices pre-filters the sorted service list. Owners and admins keep their existing visibility into their own hidden services. Tests: - TestUserCanViewServiceVisibleServiceIsPublic - TestUserCanViewServiceHiddenServiceRejectsGuest - TestUserCanViewServiceHiddenServiceRejectsForeignMember - TestUserCanViewServiceHiddenServiceAllowsOwner - TestUserCanViewServiceHiddenServiceAllowsAdmin Co-authored-by: cloudcode <cloudcode@users.noreply.github.com>
68 lines
1.4 KiB
Go
68 lines
1.4 KiB
Go
package controller
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/nezhahq/nezha/model"
|
|
"github.com/nezhahq/nezha/service/singleton"
|
|
)
|
|
|
|
func callerIsAdmin(c *gin.Context) bool {
|
|
auth, ok := c.Get(model.CtxKeyAuthorizedUser)
|
|
if !ok {
|
|
return false
|
|
}
|
|
user, ok := auth.(*model.User)
|
|
if !ok || user == nil {
|
|
return false
|
|
}
|
|
return user.Role.IsAdmin()
|
|
}
|
|
|
|
func userCanViewServer(c *gin.Context, server *model.Server) bool {
|
|
if server == nil {
|
|
return false
|
|
}
|
|
if callerIsAdmin(c) {
|
|
return true
|
|
}
|
|
if _, isMember := c.Get(model.CtxKeyAuthorizedUser); isMember {
|
|
if server.HasPermission(c) {
|
|
return true
|
|
}
|
|
return !server.HideForGuest
|
|
}
|
|
return !server.HideForGuest
|
|
}
|
|
|
|
func userCanViewService(c *gin.Context, service *model.Service) bool {
|
|
if service == nil {
|
|
return false
|
|
}
|
|
if service.EnableShowInService {
|
|
return true
|
|
}
|
|
if callerIsAdmin(c) {
|
|
return true
|
|
}
|
|
if _, isMember := c.Get(model.CtxKeyAuthorizedUser); isMember {
|
|
return service.HasPermission(c)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func assertOwnsNotificationGroup(c *gin.Context, groupID uint64) error {
|
|
if groupID == 0 {
|
|
return nil
|
|
}
|
|
|
|
var ng model.NotificationGroup
|
|
if err := singleton.DB.First(&ng, groupID).Error; err != nil {
|
|
return singleton.Localizer.ErrorT("notification group id %d does not exist", groupID)
|
|
}
|
|
if !ng.HasPermission(c) {
|
|
return singleton.Localizer.ErrorT("permission denied")
|
|
}
|
|
return nil
|
|
}
|