fix:修复文件管理可能导致的越权操作

This commit is contained in:
martin committed 2026-07-25 20:10:35 +08:00
1 parent 48c72f1eb4
commit 75bc4038db
6 files changed
+35 -20

No files matched your search

+1 -1
View File
@@ -185,7 +185,7 @@ func deleteExpiredFiles(ctx context.Context, fileSvc *common.FileService, cutoff
for _, f := range batch {
if fileSvc != nil {
// FileService.Delete 删对象(失败仅告警)后删行;返回硬错误表示行未删。
if err := fileSvc.Delete(ctx, f.ID); err != nil {
if err := fileSvc.Delete(ctx, f.ID, 0); err != nil {
g.Log().Warningf(ctx, "file retention: delete file %d failed: %v", f.ID, err)
continue
}
+3 -3
View File
@@ -174,9 +174,9 @@ func (s *sAdmin) FileDownload(ctx context.Context, req *v1.FileDownloadReq) (*v1
}
var url string
if req.Variant == "thumb" {
url, err = svc.GetThumbnailURL(ctx, req.Id, req.Width)
url, err = svc.GetThumbnailURL(ctx, req.Id, req.Width, 0)
} else {
url, err = svc.GetDownloadURL(ctx, req.Id)
url, err = svc.GetDownloadURL(ctx, req.Id, 0)
}
if err != nil {
return nil, err
@@ -198,7 +198,7 @@ func (s *sAdmin) FileDelete(ctx context.Context, req *v1.FileDeleteReq) (*v1.Fil
if err != nil {
return nil, err
}
if err := svc.Delete(ctx, req.Id); err != nil {
if err := svc.Delete(ctx, req.Id, 0); err != nil {
return nil, err
}
return &v1.FileDeleteRes{}, nil
+27 -12
View File
@@ -176,11 +176,16 @@ func (s *FileService) serveURL(fileID int64, thumb bool, width int) string {
//
// 对象存储走预签名 URL(OSS/S3/COS 直接访问桶);local provider 不支持预签名,
// 返回应用层 serve 端点的相对 URL(由 handler 鉴权后流式返回内容)。
func (s *FileService) GetDownloadURL(ctx context.Context, fileID int64) (string, error) {
//
// tenantID 用于跨租户隔离——传入该文件所属租户 ID,查询条件自动追加 tenant_id 过滤。
// 管理后台等跨租户场景传入 0 表示不做 tenant 过滤(仅按 id 查询)。
func (s *FileService) GetDownloadURL(ctx context.Context, fileID int64, tenantID int64) (string, error) {
var record *FileRecord
err := dao.FilFiles.Ctx(ctx).
Where("id", fileID).
Scan(&record)
q := dao.FilFiles.Ctx(ctx).Where("id", fileID)
if tenantID > 0 {
q = q.Where("tenant_id", tenantID)
}
err := q.Scan(&record)
if err != nil {
return "", gerror.Wrapf(err, "query file %d", fileID)
}
@@ -198,11 +203,16 @@ func (s *FileService) GetDownloadURL(ctx context.Context, fileID int64) (string,
// 非图片文件(以及不支持原生图片处理的 provider)回退到原图对象。
//
// local provider 无服务端图片处理能力,返回原图的 serve URL(前端 CSS 缩放)。
func (s *FileService) GetThumbnailURL(ctx context.Context, fileID int64, width int) (string, error) {
//
// tenantID 用于跨租户隔离——传入该文件所属租户 ID,查询条件自动追加 tenant_id 过滤。
// 管理后台等跨租户场景传入 0 表示不做 tenant 过滤(仅按 id 查询)。
func (s *FileService) GetThumbnailURL(ctx context.Context, fileID int64, width int, tenantID int64) (string, error) {
var record *FileRecord
err := dao.FilFiles.Ctx(ctx).
Where("id", fileID).
Scan(&record)
q := dao.FilFiles.Ctx(ctx).Where("id", fileID)
if tenantID > 0 {
q = q.Where("tenant_id", tenantID)
}
err := q.Scan(&record)
if err != nil {
return "", gerror.Wrapf(err, "query file %d", fileID)
}
@@ -225,11 +235,16 @@ func (s *FileService) GetThumbnailURL(ctx context.Context, fileID int64, width i
}
// Delete 从存储中删除文件并删除其元数据记录。
func (s *FileService) Delete(ctx context.Context, fileID int64) error {
//
// tenantID 用于跨租户隔离——传入该文件所属租户 ID,查询条件自动追加 tenant_id 过滤。
// 管理后台的保留期清理等跨租户场景传入 0 表示不做 tenant 过滤(仅按 id 查询)。
func (s *FileService) Delete(ctx context.Context, fileID int64, tenantID int64) error {
var record *FileRecord
err := dao.FilFiles.Ctx(ctx).
Where("id", fileID).
Scan(&record)
q := dao.FilFiles.Ctx(ctx).Where("id", fileID)
if tenantID > 0 {
q = q.Where("tenant_id", tenantID)
}
err := q.Scan(&record)
if err != nil {
return gerror.Wrapf(err, "query file %d", fileID)
}
+2 -2
View File
@@ -51,10 +51,10 @@ func TaskResultImageURLs(ctx context.Context, tenantID int64, publicTaskID strin
if thumbWidth <= 0 {
thumbWidth = 600
}
if u, e := svc.GetThumbnailURL(ctx, rec.ID, thumbWidth); e == nil {
if u, e := svc.GetThumbnailURL(ctx, rec.ID, thumbWidth, tenantID); e == nil {
thumbURL = u
}
if u, e := svc.GetDownloadURL(ctx, rec.ID); e == nil {
if u, e := svc.GetDownloadURL(ctx, rec.ID, tenantID); e == nil {
originalURL = u
}
return thumbURL, originalURL
+1 -1
View File
@@ -128,7 +128,7 @@ func handleDataExport(ctx context.Context, payload json.RawMessage) (any, error)
}
// 下载链接:local 返回应用层 serve 相对 URL,OSS 返回预签名 URL(前端按是否 http 分支)。
downloadURL, err := svc.GetDownloadURL(ctx, rec.ID)
downloadURL, err := svc.GetDownloadURL(ctx, rec.ID, p.TenantID)
if err != nil {
g.Log().Warningf(ctx, "data export: get download url for tenant %d: %v", p.TenantID, err)
}
+1 -1
View File
@@ -751,7 +751,7 @@ func rehostImage(ctx context.Context, job *SyncImageJob, data []byte, contentTyp
if err != nil {
return "", err
}
return fs.GetDownloadURL(ctx, rec.ID)
return fs.GetDownloadURL(ctx, rec.ID, job.TenantID)
}
// syncImageDownloadClient 用于从上游返回的图片 URL 下载**已生成好的**图片做 re-host。