Files

144 lines
3.9 KiB
Go

package files
import (
"context"
"encoding/base64"
"encoding/json"
"hash/crc32"
"net/http"
"os"
"strconv"
"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/journal"
"github.com/mickael-kerjean/filestash/server/pkg/permissions"
)
type FileInfo struct {
Name string `json:"name"`
Type string `json:"type"`
Size int64 `json:"size"`
Time int64 `json:"time"`
Offline bool `json:"offline,omitempty"`
Metadata any `json:"metadata,omitempty"`
}
func FileLs(ctx *App, res http.ResponseWriter, req *http.Request) {
if permissions.CanRead(ctx) == false {
if permissions.CanUpload(ctx) == false {
Log.Debug("ls::permission 'permission denied'")
SendErrorResult(res, ErrPermissionDenied)
return
}
SendSuccessResults(res, make([]FileInfo, 0))
return
}
path, err := PathBuilder(ctx, req.URL.Query().Get("path"))
if err != nil {
Log.Debug("ls::path '%s'", err.Error())
SendErrorResult(res, err)
return
}
op := journal.PublishFS(ctx, req, "ls", path)
defer op.Close(res)
perms := Metadata{}
if obj, ok := ctx.Backend.(interface{ Meta(path string) Metadata }); ok {
perms = obj.Meta(path)
}
for _, auth := range Hooks.Get.AuthorisationMiddleware() {
if err = auth.Ls(ctx, path); err != nil {
Log.Info("ls::auth '%s'", err.Error())
SendErrorResult(res, err)
return
}
ctx.Context = context.WithValue(ctx.Context, "AUDIT", false)
if err = auth.Mkdir(ctx, path); err != nil {
perms.CanCreateDirectory = NewBool(false)
}
if err = auth.Touch(ctx, path); err != nil {
perms.CanCreateFile = NewBool(false)
}
if err = auth.Mv(ctx, path, path); err != nil {
perms.CanRename = NewBool(false)
perms.CanMove = NewBool(false)
}
if err = auth.Save(ctx, path); err != nil {
perms.CanUpload = NewBool(false)
}
if err = auth.Rm(ctx, path); err != nil {
perms.CanDelete = NewBool(false)
}
if err = auth.Cat(ctx, path); err != nil {
perms.CanSee = NewBool(false)
}
ctx.Context = context.WithValue(ctx.Context, "AUDIT", nil)
}
if permissions.CanEdit(ctx) == false {
perms.CanCreateFile = NewBool(false)
perms.CanCreateDirectory = NewBool(false)
perms.CanRename = NewBool(false)
perms.CanMove = NewBool(false)
perms.CanDelete = NewBool(false)
perms.CanUpload = NewBool(false)
}
if permissions.CanUpload(ctx) == false {
perms.CanCreateDirectory = NewBool(false)
perms.CanRename = NewBool(false)
perms.CanMove = NewBool(false)
perms.CanDelete = NewBool(false)
perms.CanUpload = NewBool(false)
}
entries, err := ctx.Backend.Ls(path)
if err != nil {
Log.Debug("ls::backend '%s'", err.Error())
SendErrorResult(res, err)
return
}
files := make([]FileInfo, len(entries))
etagger := crc32.NewIEEE()
json.NewEncoder(etagger).Encode(perms)
etagger.Write([]byte(path + strconv.Itoa(len(entries))))
for i := 0; i < len(entries); i++ {
name := entries[i].Name()
files[i] = FileInfo{
Name: name,
Size: entries[i].Size(),
Time: func(mt time.Time) (modTime int64) {
if mt.IsZero() == false {
modTime = mt.UnixNano() / int64(time.Millisecond)
}
etagger.Write([]byte(name + strconv.Itoa(int(modTime))))
return modTime
}(entries[i].ModTime()),
Type: func(mode os.FileMode) string {
if mode.IsRegular() {
return "file"
}
return "directory"
}(entries[i].Mode()),
}
switch file := entries[i].(type) {
case File:
files[i].Offline = file.Offline
files[i].Metadata = file.Metadata
default:
files[i].Metadata = file.Sys()
}
}
etagValue := base64.StdEncoding.EncodeToString(etagger.Sum(nil))
res.Header().Set("Etag", etagValue)
if etagValue != "" && req.Header.Get("If-None-Match") == etagValue {
res.WriteHeader(http.StatusNotModified)
return
}
SendSuccessResultsWithMetadata(res, files, perms)
}