mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-19 16:14:39 +00:00
chore (maintenance): cleanup up webdav share
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user