fix: prevent user permission escalation

This commit is contained in:
loveuer
2026-09-09 21:00:41 -07:00
parent d3016b94db
commit fa4357a3f2
4 changed files with 103 additions and 8 deletions
+42
View File
@@ -138,6 +138,36 @@ func (a *App) manageUsers(c *gin.Context) {
c.Next()
}
func permissionsWithin(actor *User, canManageUsers, canUpload, canAdvancedUpload bool) bool {
if canManageUsers && !actor.CanManageUsers {
return false
}
if canAdvancedUpload && !actor.CanAdvancedUpload {
return false
}
return !canUpload || actor.CanUpload || actor.CanAdvancedUpload
}
func canManageTarget(actor, target *User) bool {
return permissionsWithin(actor, target.CanManageUsers, target.CanUpload, target.CanAdvancedUpload)
}
func requireAssignablePermissions(c *gin.Context, canManageUsers, canUpload, canAdvancedUpload bool) bool {
if permissionsWithin(currentUser(c), canManageUsers, canUpload, canAdvancedUpload) {
return true
}
c.JSON(http.StatusForbidden, gin.H{"error": "不能授予自己不具备的权限"})
return false
}
func requireManageableTarget(c *gin.Context, target *User) bool {
if canManageTarget(currentUser(c), target) {
return true
}
c.JSON(http.StatusForbidden, gin.H{"error": "不能管理权限高于自己的用户"})
return false
}
type loginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -562,6 +592,9 @@ func (a *App) createUser(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "用户名需为 3 到 32 位字母、数字、点、横线或下划线"})
return
}
if !requireAssignablePermissions(c, req.CanManageUsers, req.CanUpload, req.CanAdvancedUpload) {
return
}
password, err := randomToken(12)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "创建用户失败"})
@@ -600,6 +633,9 @@ func (a *App) updateUser(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
if !requireManageableTarget(c, &user) || !requireAssignablePermissions(c, req.CanManageUsers, req.CanUpload, req.CanAdvancedUpload) {
return
}
err := a.db.Model(&user).Updates(map[string]any{"username": req.Username, "can_manage_users": req.CanManageUsers, "can_upload": req.CanUpload, "can_advanced_upload": req.CanAdvancedUpload}).Error
if err != nil {
c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"})
@@ -619,6 +655,9 @@ func (a *App) resetPassword(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
if !requireManageableTarget(c, &user) {
return
}
password, err := randomToken(12)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "重置密码失败"})
@@ -653,6 +692,9 @@ func (a *App) deleteUser(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
if !requireManageableTarget(c, &user) {
return
}
var files []SharedFile
if err := a.db.Where("owner_id = ?", id).Find(&files).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除用户失败"})