mirror of https://github.com/cloudreve/Cloudreve
Fix: download archived file anonymously
parent
00ef240bea
commit
c102c74d6d
|
@ -27,6 +27,7 @@ type Group struct {
|
||||||
type GroupOption struct {
|
type GroupOption struct {
|
||||||
ArchiveDownloadEnabled bool `json:"archive_download"`
|
ArchiveDownloadEnabled bool `json:"archive_download"`
|
||||||
ArchiveTaskEnabled bool `json:"archive_task"`
|
ArchiveTaskEnabled bool `json:"archive_task"`
|
||||||
|
OneTimeDownloadEnabled bool `json:"one_time_download"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAria2Option 获取用户离线下载设备
|
// GetAria2Option 获取用户离线下载设备
|
||||||
|
|
|
@ -38,13 +38,16 @@ func (fs *FileSystem) Compress(ctx context.Context, folderIDs, fileIDs []uint) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建临时压缩文件
|
// 创建临时压缩文件
|
||||||
zipFilePath := filepath.Join(model.GetSettingByName("temp_path"), fmt.Sprintf("archive_%d.zip", time.Now().UnixNano()))
|
zipFilePath := filepath.Join(
|
||||||
|
model.GetSettingByName("temp_path"),
|
||||||
|
fmt.Sprintf("archive_%d.zip", time.Now().UnixNano()),
|
||||||
|
)
|
||||||
zipFile, err := util.CreatNestedFile(zipFilePath)
|
zipFile, err := util.CreatNestedFile(zipFilePath)
|
||||||
defer zipFile.Close()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.Log().Warning("%s", err)
|
util.Log().Warning("%s", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
defer zipFile.Close()
|
||||||
|
|
||||||
// 创建压缩文件Writer
|
// 创建压缩文件Writer
|
||||||
zipWriter := zip.NewWriter(zipFile)
|
zipWriter := zip.NewWriter(zipFile)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package filesystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"github.com/HFO4/cloudreve/models"
|
"github.com/HFO4/cloudreve/models"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
|
@ -121,10 +120,11 @@ func (fs *FileSystem) dispatchHandler() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileSystemFromContext 从gin.Context创建文件系统
|
// NewFileSystemFromContext 从gin.Context创建文件系统
|
||||||
|
// TODO 用户不存在时使用匿名文件系统
|
||||||
func NewFileSystemFromContext(c *gin.Context) (*FileSystem, error) {
|
func NewFileSystemFromContext(c *gin.Context) (*FileSystem, error) {
|
||||||
user, exist := c.Get("user")
|
user, exist := c.Get("user")
|
||||||
if !exist {
|
if !exist {
|
||||||
return nil, errors.New("无法找到用户")
|
return NewAnonymousFileSystem()
|
||||||
}
|
}
|
||||||
fs, err := NewFileSystem(user.(*model.User))
|
fs, err := NewFileSystem(user.(*model.User))
|
||||||
return fs, err
|
return fs, err
|
||||||
|
|
|
@ -40,6 +40,7 @@ type group struct {
|
||||||
AllowShare bool `json:"allowShare"`
|
AllowShare bool `json:"allowShare"`
|
||||||
AllowRemoteDownload bool `json:"allowRemoteDownload"`
|
AllowRemoteDownload bool `json:"allowRemoteDownload"`
|
||||||
AllowTorrentDownload bool `json:"allowTorrentDownload"`
|
AllowTorrentDownload bool `json:"allowTorrentDownload"`
|
||||||
|
AllowArchiveDownload bool `json:"allowArchiveDownload"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type storage struct {
|
type storage struct {
|
||||||
|
@ -72,6 +73,7 @@ func BuildUser(user model.User) User {
|
||||||
AllowShare: user.Group.ShareEnabled,
|
AllowShare: user.Group.ShareEnabled,
|
||||||
AllowRemoteDownload: aria2Option[0],
|
AllowRemoteDownload: aria2Option[0],
|
||||||
AllowTorrentDownload: aria2Option[2],
|
AllowTorrentDownload: aria2Option[2],
|
||||||
|
AllowArchiveDownload: user.Group.OptionsSerialized.ArchiveDownloadEnabled,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"github.com/HFO4/cloudreve/middleware"
|
"github.com/HFO4/cloudreve/middleware"
|
||||||
"github.com/HFO4/cloudreve/pkg/conf"
|
"github.com/HFO4/cloudreve/pkg/conf"
|
||||||
"github.com/HFO4/cloudreve/routers/controllers"
|
"github.com/HFO4/cloudreve/routers/controllers"
|
||||||
"github.com/gin-contrib/cors"
|
|
||||||
"github.com/gin-contrib/pprof"
|
"github.com/gin-contrib/pprof"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@ -19,13 +18,13 @@ func InitRouter() *gin.Engine {
|
||||||
*/
|
*/
|
||||||
r.Use(middleware.Session(conf.SystemConfig.SessionSecret))
|
r.Use(middleware.Session(conf.SystemConfig.SessionSecret))
|
||||||
|
|
||||||
// CORS TODO: 根据配置文件来
|
//// CORS TODO: 根据配置文件来
|
||||||
r.Use(cors.New(cors.Config{
|
//r.Use(cors.New(cors.Config{
|
||||||
AllowOrigins: []string{"http://localhost:3000"},
|
// AllowOrigins: []string{"http://localhost:3000"},
|
||||||
AllowMethods: []string{"PUT", "POST", "GET", "OPTIONS"},
|
// AllowMethods: []string{"PUT", "POST", "GET", "OPTIONS"},
|
||||||
AllowHeaders: []string{"Cookie", "Content-Length", "Content-Type", "X-Path", "X-FileName"},
|
// AllowHeaders: []string{"Cookie", "Content-Length", "Content-Type", "X-Path", "X-FileName"},
|
||||||
AllowCredentials: true,
|
// AllowCredentials: true,
|
||||||
}))
|
//}))
|
||||||
|
|
||||||
// 测试模式加入Mock助手中间件
|
// 测试模式加入Mock助手中间件
|
||||||
if gin.Mode() == gin.TestMode {
|
if gin.Mode() == gin.TestMode {
|
||||||
|
@ -67,8 +66,10 @@ func InitRouter() *gin.Engine {
|
||||||
{
|
{
|
||||||
file := sign.Group("file")
|
file := sign.Group("file")
|
||||||
{
|
{
|
||||||
// 下載文件
|
// 文件外链
|
||||||
file.GET("get/:id/:name", controllers.AnonymousGetContent)
|
file.GET("get/:id/:name", controllers.AnonymousGetContent)
|
||||||
|
// 下載已经打包好的文件
|
||||||
|
file.GET("archive/:id/archive.zip", controllers.DownloadArchive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,8 +105,6 @@ func InitRouter() *gin.Engine {
|
||||||
file.GET("source/:id", controllers.GetSource)
|
file.GET("source/:id", controllers.GetSource)
|
||||||
// 打包要下载的文件
|
// 打包要下载的文件
|
||||||
file.POST("archive", controllers.Archive)
|
file.POST("archive", controllers.Archive)
|
||||||
// 下載已经打包好的文件
|
|
||||||
file.Use(middleware.SignRequired()).GET("archive/:id", controllers.DownloadArchive)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 目录
|
// 目录
|
||||||
|
|
|
@ -6,11 +6,9 @@ import (
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem"
|
"github.com/HFO4/cloudreve/pkg/filesystem"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
|
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
|
||||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,21 +46,20 @@ func (service *ArchiveDownloadService) Download(ctx context.Context, c *gin.Cont
|
||||||
return serializer.Err(serializer.CodeNotSet, err.Error(), err)
|
return serializer.Err(serializer.CodeNotSet, err.Error(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fs.User.Group.OptionsSerialized.OneTimeDownloadEnabled {
|
||||||
|
// 清理资源,删除临时文件
|
||||||
|
_ = cache.Deletes([]string{service.ID}, "archive_")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("Content-Disposition", "attachment;")
|
||||||
c.Header("Content-Type", "application/zip")
|
c.Header("Content-Type", "application/zip")
|
||||||
http.ServeContent(c.Writer, c.Request, "archive.zip", time.Now(), rs)
|
http.ServeContent(c.Writer, c.Request, "", time.Now(), rs)
|
||||||
|
|
||||||
// 检查是否需要关闭文件
|
// 检查是否需要关闭文件
|
||||||
if fc, ok := rs.(io.Closer); ok {
|
if fc, ok := rs.(io.Closer); ok {
|
||||||
err = fc.Close()
|
err = fc.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理资源,删除临时文件
|
|
||||||
_ = cache.Deletes([]string{service.ID}, "archive_")
|
|
||||||
err = os.Remove(zipPath.(string))
|
|
||||||
if err != nil {
|
|
||||||
util.Log().Warning("无法删除临时文件 %s :%s", zipPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return serializer.Response{
|
return serializer.Response{
|
||||||
Code: 0,
|
Code: 0,
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,13 +61,13 @@ func (service *ItemService) Archive(ctx context.Context, c *gin.Context) seriali
|
||||||
}
|
}
|
||||||
zipID := util.RandStringRunes(16)
|
zipID := util.RandStringRunes(16)
|
||||||
signedURI, err := auth.SignURI(
|
signedURI, err := auth.SignURI(
|
||||||
fmt.Sprintf("/api/v3/file/archive/%s", zipID),
|
fmt.Sprintf("/api/v3/file/archive/%s/archive.zip", zipID),
|
||||||
time.Now().Unix()+120,
|
time.Now().Unix()+30,
|
||||||
)
|
)
|
||||||
finalURL := siteURL.ResolveReference(signedURI).String()
|
finalURL := siteURL.ResolveReference(signedURI).String()
|
||||||
|
|
||||||
// 将压缩文件记录存入缓存
|
// 将压缩文件记录存入缓存
|
||||||
err = cache.Set("archive_"+zipID, zipFile, 120)
|
err = cache.Set("archive_"+zipID, zipFile, 30)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serializer.Err(serializer.CodeIOFailed, "无法写入缓存", err)
|
return serializer.Err(serializer.CodeIOFailed, "无法写入缓存", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue