chore (maintenance): cleanup up webdav share

This commit is contained in:
MickaelK
2026-09-30 12:31:07 +10:00
parent 638ac8bd4b
commit dfdb2d2e06
2 changed files with 46 additions and 102 deletions
+30 -88
View File
@@ -3,12 +3,13 @@ package share
import (
"net/http"
"path/filepath"
"slices"
"strings"
. "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"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
"github.com/mickael-kerjean/net/webdav"
)
@@ -19,47 +20,28 @@ func WebdavHandler(ctx *App, res http.ResponseWriter, req *http.Request) {
return
}
// https://github.com/golang/net/blob/master/webdav/webdav.go#L49-L68
canRead := permissions.CanRead(ctx)
canWrite := permissions.CanEdit(ctx)
canUpload := permissions.CanUpload(ctx)
var isAllowed bool
switch req.Method {
case "OPTIONS", "HEAD", "GET":
if canRead == false {
SendErrorResult(res, ErrPermissionDenied)
return
}
case "OPTIONS", "HEAD", "GET", "PROPFIND":
isAllowed = permissions.CanRead(ctx)
case "MKCOL", "DELETE", "COPY", "MOVE", "PROPPATCH":
if canWrite == false {
SendErrorResult(res, ErrPermissionDenied)
return
}
case "PROPFIND":
if canRead == false {
SendErrorResult(res, ErrPermissionDenied)
return
}
case "PUT":
if canWrite == false || canUpload == false {
SendErrorResult(res, ErrPermissionDenied)
return
}
case "LOCK", "UNLOCK":
if canWrite == false || canUpload == false {
SendErrorResult(res, ErrPermissionDenied)
return
}
isAllowed = permissions.CanEdit(ctx)
case "PUT", "LOCK", "UNLOCK":
isAllowed = permissions.CanEdit(ctx) && permissions.CanUpload(ctx)
default:
SendErrorResult(res, ErrNotImplemented)
return
}
if isAllowed == false {
SendErrorResult(res, ErrPermissionDenied)
return
}
h := &webdav.Handler{
(&webdav.Handler{
Prefix: "/s/" + ctx.Share.Id,
FileSystem: NewWebdavFs(ctx.Backend, ctx.Share.Backend, ctx.Share.Path, req),
LockSystem: NewWebdavLock(),
}
h.ServeHTTP(res, req)
}).ServeHTTP(res, req)
}
/*
@@ -69,72 +51,32 @@ func WebdavHandler(ctx *App, res http.ResponseWriter, req *http.Request) {
*/
func WebdavBlacklist(fn HandlerFunc) HandlerFunc {
return HandlerFunc(func(ctx *App, res http.ResponseWriter, req *http.Request) {
base := filepath.Base(req.URL.String())
if req.Method == "PUT" || req.Method == "MKCOL" {
if strings.HasPrefix(base, "._") {
name := filepath.Base(req.URL.String())
isAppleDouble := strings.HasPrefix(name, "._")
switch req.Method {
case "PUT", "MKCOL":
if isAppleDouble || slices.Contains([]string{".DS_Store", ".localized"}, name) {
res.WriteHeader(http.StatusMethodNotAllowed)
res.Write([]byte(""))
return
} else if base == ".DS_Store" {
res.WriteHeader(http.StatusMethodNotAllowed)
res.Write([]byte(""))
return
} else if base == ".localized" {
res.WriteHeader(http.StatusMethodNotAllowed)
res.Write([]byte(""))
return
}
} else if req.Method == "PROPFIND" {
if strings.HasPrefix(base, "._") {
res.WriteHeader(http.StatusForbidden)
return
} else if base == ".DS_Store" {
res.WriteHeader(http.StatusForbidden)
res.Write([]byte(""))
return
} else if base == ".localized" {
res.WriteHeader(http.StatusForbidden)
return
} else if base == ".ql_disablethumbnails" {
res.WriteHeader(http.StatusForbidden)
res.Write([]byte(""))
return
} else if base == ".ql_disablecache" {
res.WriteHeader(http.StatusForbidden)
return
} else if base == ".hidden" {
res.WriteHeader(http.StatusForbidden)
return
} else if base == ".Spotlight-V100" {
res.WriteHeader(http.StatusForbidden)
return
} else if base == ".metadata_never_index" {
res.WriteHeader(http.StatusForbidden)
return
} else if base == "Contents" {
res.WriteHeader(http.StatusForbidden)
return
} else if base == ".metadata_never_index_unless_rootfs" {
case "PROPFIND":
if isAppleDouble || slices.Contains([]string{
".DS_Store", ".localized", ".hidden", ".Spotlight-V100",
".ql_disablethumbnails", ".ql_disablecache",
".metadata_never_index", ".metadata_never_index_unless_rootfs",
"Contents",
}, name) {
res.WriteHeader(http.StatusForbidden)
return
}
} else if req.Method == "GET" {
if base == ".DS_Store" {
case "GET", "DELETE":
if name == ".DS_Store" {
res.WriteHeader(http.StatusForbidden)
res.Write([]byte(""))
return
}
} else if req.Method == "DELETE" {
if base == ".DS_Store" {
res.WriteHeader(http.StatusForbidden)
res.Write([]byte(""))
return
}
} else if req.Method == "LOCK" || req.Method == "UNLOCK" {
if base == ".DS_Store" {
case "LOCK", "UNLOCK":
if name == ".DS_Store" {
res.WriteHeader(http.StatusMethodNotAllowed)
res.Write([]byte(""))
return
}
}
+16 -14
View File
@@ -107,12 +107,6 @@ func (this *WebdavFs) Stat(ctx context.Context, name string) (os.FileInfo, error
return this.webdavFile.Stat()
}
fullname := this.fullpath(name)
if isMicrosoftWebDAVClient(this.req) && this.req.Method == "PROPFIND" {
if name == "" {
fullname = this.chroot
}
fullname = EnforceDirectory(fullname)
}
if fullname == "" {
return nil, os.ErrNotExist
}
@@ -125,11 +119,20 @@ func (this *WebdavFs) Stat(ctx context.Context, name string) (os.FileInfo, error
}
func (this WebdavFs) fullpath(path string) string {
p := filepath.Join(this.chroot, path)
if strings.HasSuffix(path, "/") == true && strings.HasSuffix(p, "/") == false {
p += "/"
var (
p = filepath.Join(this.chroot, path)
isPathAFolder = strings.HasSuffix(path, "/")
isChrootAFile = strings.HasSuffix(this.chroot, "/") == false
)
if isChrootAFile {
if p != this.chroot {
return ""
}
if strings.HasPrefix(p, this.chroot) == false {
return p
} else if isPathAFolder {
p = EnforceDirectory(p)
}
if strings.HasPrefix(EnforceDirectory(p), this.chroot) == false {
return ""
}
return p
@@ -219,6 +222,9 @@ func (this *WebdavFile) Stat() (os.FileInfo, error) {
for i := range files {
if files[i].Name() == baseDir {
found = true
if files[i].IsDir() {
this.path = EnforceDirectory(this.path)
}
break
}
}
@@ -336,7 +342,3 @@ func NewWebdavLock() webdav.LockSystem {
}
return lock
}
func isMicrosoftWebDAVClient(req *http.Request) bool {
return strings.HasPrefix(req.Header.Get("User-Agent"), "Microsoft-WebDAV-MiniRedir/")
}