diff --git a/pkg/filesystem/driver/onedrive/handler.go b/pkg/filesystem/driver/onedrive/handler.go index c1e8717..0820764 100644 --- a/pkg/filesystem/driver/onedrive/handler.go +++ b/pkg/filesystem/driver/onedrive/handler.go @@ -12,6 +12,7 @@ import ( "time" model "github.com/cloudreve/Cloudreve/v3/models" + "github.com/cloudreve/Cloudreve/v3/pkg/auth" "github.com/cloudreve/Cloudreve/v3/pkg/cache" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/response" @@ -155,6 +156,19 @@ func (handler Driver) Source( cacheKey := fmt.Sprintf("onedrive_source_%d_%s", handler.Policy.ID, path) if file, ok := ctx.Value(fsctx.FileModelCtx).(model.File); ok { cacheKey = fmt.Sprintf("onedrive_source_file_%d_%d", file.UpdatedAt.Unix(), file.ID) + // 如果是永久链接,则返回签名后的中转外链 + if ttl == 0 { + signedURI, err := auth.SignURI( + auth.General, + fmt.Sprintf("/api/v3/file/source/%d/%s", file.ID, file.Name), + ttl, + ) + if err != nil { + return "", err + } + return baseURL.ResolveReference(signedURI).String(), nil + } + } // 尝试从缓存中查找 diff --git a/pkg/filesystem/file.go b/pkg/filesystem/file.go index eeadadc..8216779 100644 --- a/pkg/filesystem/file.go +++ b/pkg/filesystem/file.go @@ -126,7 +126,7 @@ func (fs *FileSystem) Preview(ctx context.Context, id uint, isText bool) (*respo // 否则重定向到签名的预览URL ttl := model.GetIntSetting("preview_timeout", 60) - previewURL, err := fs.signURL(ctx, &fs.FileTarget[0], int64(ttl), false) + previewURL, err := fs.SignURL(ctx, &fs.FileTarget[0], int64(ttl), false) if err != nil { return nil, err } @@ -234,7 +234,7 @@ func (fs *FileSystem) GetDownloadURL(ctx context.Context, id uint, timeout strin // 生成下載地址 ttl := model.GetIntSetting(timeout, 60) - source, err := fs.signURL( + source, err := fs.SignURL( ctx, fileTarget, int64(ttl), @@ -264,7 +264,7 @@ func (fs *FileSystem) GetSource(ctx context.Context, fileID uint) (string, error ) } - source, err := fs.signURL(ctx, &fs.FileTarget[0], 0, false) + source, err := fs.SignURL(ctx, &fs.FileTarget[0], 0, false) if err != nil { return "", serializer.NewError(serializer.CodeNotSet, "无法获取外链", err) } @@ -272,7 +272,8 @@ func (fs *FileSystem) GetSource(ctx context.Context, fileID uint) (string, error return source, nil } -func (fs *FileSystem) signURL(ctx context.Context, file *model.File, ttl int64, isDownload bool) (string, error) { +// SignURL 签名文件原始 URL +func (fs *FileSystem) SignURL(ctx context.Context, file *model.File, ttl int64, isDownload bool) (string, error) { fs.FileTarget = []model.File{*file} ctx = context.WithValue(ctx, fsctx.FileModelCtx, *file) diff --git a/routers/controllers/file.go b/routers/controllers/file.go index ff10547..bc19497 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -88,6 +88,29 @@ func AnonymousGetContent(c *gin.Context) { } } +// AnonymousPermLink 文件签名后的永久链接 +func AnonymousPermLink(c *gin.Context) { + // 创建上下文 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var service explorer.FileAnonymousGetService + if err := c.ShouldBindUri(&service); err == nil { + res := service.Source(ctx, c) + // 是否需要重定向 + if res.Code == -302 { + c.Redirect(302, res.Data.(string)) + return + } + // 是否有错误发生 + if res.Code != 0 { + c.JSON(200, res) + } + } else { + c.JSON(200, ErrorResponse(err)) + } +} + // GetSource 获取文件的外链地址 func GetSource(c *gin.Context) { // 创建上下文 diff --git a/routers/router.go b/routers/router.go index 8cf5a9d..7b0f36e 100644 --- a/routers/router.go +++ b/routers/router.go @@ -162,8 +162,10 @@ func InitMasterRouter() *gin.Engine { { file := sign.Group("file") { - // 文件外链 + // 文件外链(直接输出文件数据) file.GET("get/:id/:name", controllers.AnonymousGetContent) + // 文件外链(301跳转) + file.GET("source/:id/:name", controllers.AnonymousPermLink) // 下載已经打包好的文件 file.GET("archive/:id/archive.zip", controllers.DownloadArchive) // 下载文件 diff --git a/service/explorer/file.go b/service/explorer/file.go index 33146ac..d128c86 100644 --- a/service/explorer/file.go +++ b/service/explorer/file.go @@ -184,6 +184,33 @@ func (service *FileAnonymousGetService) Download(ctx context.Context, c *gin.Con } } +// Source 重定向到文件的有效原始链接 +func (service *FileAnonymousGetService) Source(ctx context.Context, c *gin.Context) serializer.Response { + fs, err := filesystem.NewAnonymousFileSystem() + if err != nil { + return serializer.Err(serializer.CodeGroupNotAllowed, err.Error(), err) + } + defer fs.Recycle() + + // 查找文件 + err = fs.SetTargetFileByIDs([]uint{service.ID}) + if err != nil { + return serializer.Err(serializer.CodeNotSet, err.Error(), err) + } + + // 获取文件流 + res, err := fs.SignURL(ctx, &fs.FileTarget[0], + int64(model.GetIntSetting("preview_timeout", 60)), false) + if err != nil { + return serializer.Err(serializer.CodeNotSet, err.Error(), err) + } + + return serializer.Response{ + Code: -302, + Data: res, + } +} + // CreateDocPreviewSession 创建DOC文件预览会话,返回预览地址 func (service *FileIDService) CreateDocPreviewSession(ctx context.Context, c *gin.Context) serializer.Response { // 创建文件系统