From b6fed87d617237ec32b7491b5a2f92ca768c6a0d Mon Sep 17 00:00:00 2001 From: UUBulb <35923940+uubulb@users.noreply.github.com> Date: Thu, 28 Aug 2025 22:37:44 +0800 Subject: [PATCH] fix: member-created services shouldn't be applied to admin resources (#1113) --- cmd/dashboard/controller/controller.go | 2 +- cmd/dashboard/controller/setting.go | 6 +++--- cmd/dashboard/controller/user.go | 4 ++-- cmd/dashboard/rpc/rpc.go | 6 +++--- model/config.go | 10 +++++----- model/user.go | 12 +++++++++--- model/user_api.go | 2 +- service/singleton/alertsentinel.go | 6 +++--- 8 files changed, 27 insertions(+), 21 deletions(-) diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index 29ab671..7683a89 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -223,7 +223,7 @@ func adminHandler[T any](handler handlerFunc[T]) func(*gin.Context) { } user := *auth.(*model.User) - if user.Role != model.RoleAdmin { + if !user.Role.IsAdmin() { c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("permission denied"))) return } diff --git a/cmd/dashboard/controller/setting.go b/cmd/dashboard/controller/setting.go index 3e43d6e..427b901 100644 --- a/cmd/dashboard/controller/setting.go +++ b/cmd/dashboard/controller/setting.go @@ -24,11 +24,11 @@ func listConfig(c *gin.Context) (*model.SettingResponse, error) { var isAdmin bool if authorized { user := u.(*model.User) - isAdmin = user.Role == model.RoleAdmin + isAdmin = user.Role.IsAdmin() } config := *singleton.Conf - config.Language = strings.Replace(config.Language, "_", "-", -1) + config.Language = strings.ReplaceAll(config.Language, "_", "-") conf := model.SettingResponse{ Config: model.Setting{ @@ -89,7 +89,7 @@ func updateConfig(c *gin.Context) (any, error) { return nil, errors.New("invalid user template") } - singleton.Conf.Language = strings.Replace(sf.Language, "-", "_", -1) + singleton.Conf.Language = strings.ReplaceAll(sf.Language, "-", "_") singleton.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification singleton.Conf.EnablePlainIPInNotification = sf.EnablePlainIPInNotification diff --git a/cmd/dashboard/controller/user.go b/cmd/dashboard/controller/user.go index c2cbea8..66bdc64 100644 --- a/cmd/dashboard/controller/user.go +++ b/cmd/dashboard/controller/user.go @@ -133,7 +133,7 @@ func createUser(c *gin.Context) (uint64, error) { if uf.Username == "" { return 0, singleton.Localizer.ErrorT("username can't be empty") } - if uf.Role != model.RoleAdmin && uf.Role != model.RoleMember { + if uf.Role > model.RoleMember { return 0, singleton.Localizer.ErrorT("invalid role") } @@ -195,7 +195,7 @@ func listOnlineUser(c *gin.Context) (*model.Value[[]*model.OnlineUser], error) { var isAdmin bool u, ok := c.Get(model.CtxKeyAuthorizedUser) if ok { - isAdmin = u.(*model.User).Role == model.RoleAdmin + isAdmin = u.(*model.User).Role.IsAdmin() } limit, err := strconv.Atoi(c.Query("limit")) if err != nil || limit < 1 { diff --git a/cmd/dashboard/rpc/rpc.go b/cmd/dashboard/rpc/rpc.go index 95240ba..68c84cd 100644 --- a/cmd/dashboard/rpc/rpc.go +++ b/cmd/dashboard/rpc/rpc.go @@ -177,14 +177,14 @@ func ServeNAT(w http.ResponseWriter, r *http.Request, natConfig *model.NAT) { } func canSendTaskToServer(task *model.Service, server *model.Server) bool { - var role uint8 + var role model.Role singleton.UserLock.RLock() - if u, ok := singleton.UserInfoMap[server.UserID]; !ok { + if u, ok := singleton.UserInfoMap[task.UserID]; !ok { role = model.RoleMember } else { role = u.Role } singleton.UserLock.RUnlock() - return task.UserID == server.UserID || role == model.RoleAdmin + return task.UserID == server.UserID || role.IsAdmin() } diff --git a/model/config.go b/model/config.go index a10d57f..380cce8 100644 --- a/model/config.go +++ b/model/config.go @@ -32,10 +32,10 @@ type ConfigDashboard struct { InstallHost string `koanf:"install_host" json:"install_host,omitempty"` AgentTLS bool `koanf:"tls" json:"tls,omitempty"` // 用于前端判断生成的安装命令是否启用 TLS - WebRealIPHeader string `koanf:"web_real_ip_header" json:"web_real_ip_header,omitempty"` // 前端真实IP - AgentRealIPHeader string `koanf:"agent_real_ip_header" json:"agent_real_ip_header,omitempty"` // Agent真实IP - UserTemplate string `koanf:"user_template" json:"user_template,omitempty"` - AdminTemplate string `koanf:"admin_template" json:"admin_template,omitempty"` + WebRealIPHeader string `koanf:"web_real_ip_header" json:"web_real_ip_header,omitempty"` // 前端真实IP + AgentRealIPHeader string `koanf:"agent_real_ip_header" json:"agent_real_ip_header,omitempty"` // Agent真实IP + UserTemplate string `koanf:"user_template" json:"user_template,omitempty"` + AdminTemplate string `koanf:"admin_template" json:"admin_template,omitempty"` EnablePlainIPInNotification bool `koanf:"enable_plain_ip_in_notification" json:"enable_plain_ip_in_notification,omitempty"` // 通知信息IP不打码 @@ -87,7 +87,7 @@ func (c *Config) Read(path string, frontendTemplates []FrontendTemplate) error { c.filePath = path err := c.k.Load(env.Provider("NZ_", ".", func(s string) string { - return strings.Replace(strings.ToLower(strings.TrimPrefix(s, "NZ_")), "_", ".", -1) + return strings.ReplaceAll(strings.ToLower(strings.TrimPrefix(s, "NZ_")), "_", ".") }), nil) if err != nil { return err diff --git a/model/user.go b/model/user.go index 3d07b79..2c40563 100644 --- a/model/user.go +++ b/model/user.go @@ -8,8 +8,14 @@ import ( "gorm.io/gorm" ) +type Role uint8 + +func (r Role) IsAdmin() bool { + return r == RoleAdmin +} + const ( - RoleAdmin uint8 = iota + RoleAdmin Role = iota RoleMember ) @@ -19,13 +25,13 @@ type User struct { Common Username string `json:"username,omitempty" gorm:"uniqueIndex"` Password string `json:"password,omitempty" gorm:"type:char(72)"` - Role uint8 `json:"role,omitempty"` + Role Role `json:"role,omitempty"` AgentSecret string `json:"agent_secret,omitempty" gorm:"type:char(32)"` RejectPassword bool `json:"reject_password,omitempty"` } type UserInfo struct { - Role uint8 + Role Role AgentSecret string } diff --git a/model/user_api.go b/model/user_api.go index c7fac9e..38972a8 100644 --- a/model/user_api.go +++ b/model/user_api.go @@ -1,7 +1,7 @@ package model type UserForm struct { - Role uint8 `json:"role,omitempty"` + Role Role `json:"role,omitempty"` Username string `json:"username,omitempty"` Password string `json:"password,omitempty" gorm:"type:char(72)"` } diff --git a/service/singleton/alertsentinel.go b/service/singleton/alertsentinel.go index 36d3ba9..c31873c 100644 --- a/service/singleton/alertsentinel.go +++ b/service/singleton/alertsentinel.go @@ -142,14 +142,14 @@ func checkStatus() { for _, server := range m { // 监测点 UserLock.RLock() - var role uint8 - if u, ok := UserInfoMap[server.UserID]; !ok { + var role model.Role + if u, ok := UserInfoMap[alert.UserID]; !ok { role = model.RoleMember } else { role = u.Role } UserLock.RUnlock() - if alert.UserID != server.UserID && role != model.RoleAdmin { + if alert.UserID != server.UserID && !role.IsAdmin() { continue } alertsStore[alert.ID][server.ID] = append(alertsStore[alert.