fix(objectstore): decouple WebDAV targetPath from logical storage key and fix basePath duplication

- WebDAV Put now returns PutResult with driver-agnostic logical relative key (relKey), keeping database records decoupled from mount basePath.
- targetPath mounts logical keys to the remote WebDAV server path, and transparently handles legacy database records containing basePath or duplicate basePath prefixes.
- Make localBackend path resolution resilient to keys with leading slashes or legacy absolute paths outside local root by safely mounting them as relative paths.
- Add comprehensive unit tests for WebDAV targetPath, relKey, end-to-end roundtrip with in-memory WebDAV server, and local storage leading slash handling.
This commit is contained in:
ryan
2026-09-22 14:16:21 +08:00
parent 96abbf180d
commit aad059ab6e
4 changed files with 331 additions and 25 deletions
+16 -14
View File
@@ -91,30 +91,32 @@ func (b *localBackend) Test(_ context.Context) error {
return os.MkdirAll(b.root, storageDirPerm)
}
func isWithinRoot(root, target string) bool {
absRoot, err := filepath.Abs(root)
if err != nil {
return false
}
absTarget, err := filepath.Abs(target)
if err != nil {
return false
}
rel, err := filepath.Rel(absRoot, absTarget)
return err == nil && !strings.HasPrefix(rel, "..")
}
func (b *localBackend) path(key string) (string, error) {
if filepath.IsAbs(key) {
cleanPath := filepath.Clean(key)
absRoot, err := filepath.Abs(b.root)
if err != nil {
return "", err
if isWithinRoot(b.root, cleanPath) {
return cleanPath, nil
}
absPath, err := filepath.Abs(cleanPath)
if err != nil {
return "", err
}
rel, err := filepath.Rel(absRoot, absPath)
if err != nil || strings.HasPrefix(rel, "..") {
return "", errors.New("storage key escapes local root")
}
return cleanPath, nil
}
cleanKey := filepath.Clean(filepath.FromSlash(strings.TrimPrefix(key, "/")))
if cleanKey == "." || cleanKey == "" || strings.HasPrefix(cleanKey, "..") {
return "", fmt.Errorf("invalid local storage key %q", key)
}
path := filepath.Join(b.root, cleanKey)
rel, err := filepath.Rel(b.root, path)
if err != nil || strings.HasPrefix(rel, "..") {
if !isWithinRoot(b.root, path) {
return "", errors.New("storage key escapes local root")
}
return path, nil