mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-20 00:15:40 +00:00
130 lines
4.2 KiB
Go
130 lines
4.2 KiB
Go
package files
|
|
|
|
import (
|
|
"archive/zip"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
. "github.com/mickael-kerjean/filestash/server/pkg/core"
|
|
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
|
|
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
|
|
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
|
|
)
|
|
|
|
func FileDownloader(ctx *App, res http.ResponseWriter, req *http.Request) {
|
|
var err error
|
|
if CanRead(ctx) == false {
|
|
Log.Debug("downloader::permission 'permission denied'")
|
|
SendErrorResult(res, ErrPermissionDenied)
|
|
return
|
|
}
|
|
paths := req.URL.Query()["path"]
|
|
for i := 0; i < len(paths); i++ {
|
|
if paths[i], err = PathBuilder(ctx, paths[i]); err != nil {
|
|
Log.Debug("downloader::path '%s'", err.Error())
|
|
SendErrorResult(res, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
resHeader := res.Header()
|
|
resHeader.Set("Content-Type", "application/zip")
|
|
filename := "download"
|
|
if len(paths) == 1 {
|
|
filename = filepath.Base(paths[0])
|
|
}
|
|
resHeader.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", filename))
|
|
|
|
start := time.Now()
|
|
var addToZipRecursive func(*App, *zip.Writer, string, string, *[]string) error
|
|
addToZipRecursive = func(c *App, zw *zip.Writer, backendPath string, zipRoot string, errList *[]string) (err error) {
|
|
if time.Since(start) > time.Duration(zip_timeout())*time.Second {
|
|
Log.Debug("downloader::timeout zip not completed due to timeout")
|
|
return ErrTimeout
|
|
}
|
|
if strings.HasSuffix(backendPath, "/") == false {
|
|
// Process File
|
|
zipPath := strings.TrimPrefix(backendPath, zipRoot)
|
|
file, err := ctx.Backend.Cat(backendPath)
|
|
if err != nil {
|
|
*errList = append(*errList, fmt.Sprintf("downloader::cat %s %s\n", zipPath, err.Error()))
|
|
if err == ErrNotReachable {
|
|
return nil
|
|
}
|
|
Log.Debug("downloader::cat backendPath['%s'] zipPath['%s'] error['%s']", backendPath, zipPath, err.Error())
|
|
return err
|
|
}
|
|
zipFile, err := zw.Create(zipPath)
|
|
if err != nil {
|
|
*errList = append(*errList, fmt.Sprintf("downloader::create %s %s\n", zipPath, err.Error()))
|
|
Log.Debug("downloader::create backendPath['%s'] zipPath['%s'] error['%s']", backendPath, zipPath, err.Error())
|
|
return err
|
|
}
|
|
if _, err = io.Copy(zipFile, file); err != nil {
|
|
*errList = append(*errList, fmt.Sprintf("downloader::copy %s %s\n", zipPath, err.Error()))
|
|
Log.Debug("downloader::copy backendPath['%s'] zipPath['%s'] error['%s']", backendPath, zipPath, err.Error())
|
|
io.Copy(zipFile, strings.NewReader(""))
|
|
return err
|
|
}
|
|
file.Close()
|
|
return nil
|
|
}
|
|
// Process Folder
|
|
entries, err := c.Backend.Ls(backendPath)
|
|
if err != nil {
|
|
*errList = append(*errList, fmt.Sprintf("downloader::ls %s\n", err.Error()))
|
|
Log.Debug("downloader::ls path['%s'] error['%s']", backendPath, err.Error())
|
|
return err
|
|
}
|
|
for i := 0; i < len(entries); i++ {
|
|
newBackendPath := backendPath + entries[i].Name()
|
|
if entries[i].IsDir() {
|
|
newBackendPath += "/"
|
|
}
|
|
if err = addToZipRecursive(ctx, zw, newBackendPath, zipRoot, errList); err != nil {
|
|
*errList = append(*errList, fmt.Sprintf("downloader::recursive %s\n", err.Error()))
|
|
Log.Debug("downloader::recursive path['%s'] error['%s']", newBackendPath, err.Error())
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
zipWriter := zip.NewWriter(res)
|
|
defer zipWriter.Close()
|
|
errList := []string{}
|
|
for i := 0; i < len(paths); i++ {
|
|
zipRoot := ""
|
|
if strings.HasSuffix(paths[i], "/") {
|
|
zipRoot = strings.TrimSuffix(paths[i], filepath.Base(paths[i])+"/")
|
|
} else {
|
|
zipRoot = strings.TrimSuffix(paths[i], filepath.Base(paths[i]))
|
|
}
|
|
|
|
for _, auth := range Hooks.Get.AuthorisationMiddleware() {
|
|
if err = auth.Ls(ctx, paths[i]); err != nil {
|
|
Log.Info("downloader::ls::auth path['%s'] => '%s'", paths[i], err.Error())
|
|
SendErrorResult(res, ErrNotAuthorized)
|
|
return
|
|
}
|
|
if err = auth.Cat(ctx, paths[i]); err != nil {
|
|
Log.Info("downloader::cat::auth path['%s'] => '%s'", paths[i], err.Error())
|
|
SendErrorResult(res, ErrNotAuthorized)
|
|
return
|
|
}
|
|
}
|
|
addToZipRecursive(ctx, zipWriter, paths[i], zipRoot, &errList)
|
|
}
|
|
if len(errList) > 0 {
|
|
if errorWriter, err := zipWriter.Create("error.log"); err == nil {
|
|
for _, e := range errList {
|
|
io.Copy(errorWriter, strings.NewReader(e))
|
|
}
|
|
}
|
|
}
|
|
}
|