fix: prevent user permission escalation
This commit is contained in:
@@ -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": "删除用户失败"})
|
||||
|
||||
Reference in New Issue
Block a user