安全: 修复凭据、遥测与账号数据清理风险
This commit is contained in:
+56
-8
@@ -1011,7 +1011,8 @@ func (db *users) BanUserAndCleanup(ctx context.Context, userID uint) error {
|
||||
}
|
||||
|
||||
// purgeUserContent 物理删除某用户的全部内容数据:追问、消息与消息图片、私聊会话、
|
||||
// 提问-图片关联、提问、拉黑关系、功能开关。**不含用户行本身**(由调用方决定是软删除还是物理删除)。
|
||||
// 提问图片元数据及关联、提问、投票及其子表、访问统计、拉黑关系、功能开关。
|
||||
// **不含用户行本身**(由调用方决定是软删除还是物理删除),也不删除审计/处置记录。
|
||||
//
|
||||
// 全部使用 Unscoped 物理删除而非软删除:这些表多为软删除模型,而部分表的唯一索引
|
||||
// 不含 deleted_at(如 conversations.token),软删除会让被删行永久占据唯一槽位。
|
||||
@@ -1027,18 +1028,18 @@ func purgeUserContent(ctx context.Context, tx *gorm.DB, userID uint) error {
|
||||
return errors.Wrap(err, "delete follow ups of user")
|
||||
}
|
||||
|
||||
// 消息图片必须先于消息删除,否则消息子查询将无法再匹配待删图片。
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("message_id IN (SELECT id FROM messages WHERE conversation_id IN (SELECT id FROM conversations WHERE owner_id = ? OR asker_id = ?))", userID, userID).
|
||||
Delete(&MessageImage{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete message images of user")
|
||||
}
|
||||
// 消息:属于该用户作为 owner 或 asker 的会话
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("conversation_id IN (SELECT id FROM conversations WHERE owner_id = ? OR asker_id = ?)", userID, userID).
|
||||
Delete(&Message{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete messages of user")
|
||||
}
|
||||
// 消息图片
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("message_id IN (SELECT id FROM messages WHERE conversation_id IN (SELECT id FROM conversations WHERE owner_id = ? OR asker_id = ?))", userID, userID).
|
||||
Delete(&MessageImage{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete message images of user")
|
||||
}
|
||||
|
||||
// 私聊会话
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
@@ -1047,7 +1048,25 @@ func purgeUserContent(ctx context.Context, tx *gorm.DB, userID uint) error {
|
||||
return errors.Wrap(err, "delete conversations of user")
|
||||
}
|
||||
|
||||
// 提问-图片关联(仅删除关联记录;UploadImage 本体为通用资源,保留)
|
||||
// 提问图片元数据:删除本用户上传的孤立图片,以及仅链接到本用户提问的图片。
|
||||
// 仍被其他提问引用的图片必须保留;这里只清数据库元数据,不操作对象存储。
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where(`(
|
||||
uploader_user_id = ?
|
||||
OR upload_images.id IN (
|
||||
SELECT upload_image_id FROM upload_image_questions
|
||||
WHERE question_id IN (SELECT id FROM questions WHERE user_id = ?)
|
||||
)
|
||||
) AND NOT EXISTS (
|
||||
SELECT 1 FROM upload_image_questions AS shared_links
|
||||
WHERE shared_links.upload_image_id = upload_images.id
|
||||
AND shared_links.question_id NOT IN (SELECT id FROM questions WHERE user_id = ?)
|
||||
)`, userID, userID, userID).
|
||||
Delete(&UploadImage{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete upload images of user")
|
||||
}
|
||||
|
||||
// 提问-图片关联
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("question_id IN (SELECT id FROM questions WHERE user_id = ?)", userID).
|
||||
Delete(&UploadImageQuestion{}).Error; err != nil {
|
||||
@@ -1061,6 +1080,35 @@ func purgeUserContent(ctx context.Context, tx *gorm.DB, userID uint) error {
|
||||
return errors.Wrap(err, "delete questions of user")
|
||||
}
|
||||
|
||||
// 投票子表必须先于投票主表删除;只处理该用户拥有的投票,不按参与者身份扩大范围。
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("vote_id IN (SELECT id FROM votes WHERE user_id = ?)", userID).
|
||||
Delete(&VoteSubmission{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete vote submissions of user")
|
||||
}
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("vote_id IN (SELECT id FROM votes WHERE user_id = ?)", userID).
|
||||
Delete(&VoteFormField{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete vote form fields of user")
|
||||
}
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("vote_id IN (SELECT id FROM votes WHERE user_id = ?)", userID).
|
||||
Delete(&VoteOption{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete vote options of user")
|
||||
}
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("user_id = ?", userID).
|
||||
Delete(&Vote{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete votes of user")
|
||||
}
|
||||
|
||||
// 提问箱访问统计:user_id 明确指向箱主,不属于站方审计/处置记录。
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("user_id = ?", userID).
|
||||
Delete(&BoxView{}).Error; err != nil {
|
||||
return errors.Wrap(err, "delete box views of user")
|
||||
}
|
||||
|
||||
// 拉黑关系(该用户拉黑别人,或被别人拉黑)
|
||||
if err := tx.WithContext(ctx).Unscoped().
|
||||
Where("user_id = ? OR blocked_id = ?", userID, userID).
|
||||
|
||||
Reference in New Issue
Block a user