All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m15s
57 lines
1.8 KiB
Go
57 lines
1.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var numberSuffixRegex = regexp.MustCompile(` \(\d+\)$`)
|
|
|
|
// GetUniquePath checks if a file or folder exists at the given baseDir with the given name.
|
|
// If it does, it systematically appends " (1)", " (2)", etc., until it finds an available name.
|
|
// It returns the unique filename.
|
|
func GetUniquePath(baseDir, name string) string {
|
|
ext := filepath.Ext(name)
|
|
base := name[:len(name)-len(ext)]
|
|
|
|
finalPath := filepath.Join(baseDir, name)
|
|
if _, err := os.Stat(finalPath); os.IsNotExist(err) {
|
|
return name
|
|
}
|
|
|
|
base = numberSuffixRegex.ReplaceAllString(base, "")
|
|
|
|
for i := 1; ; i++ {
|
|
newName := fmt.Sprintf("%s (%d)%s", base, i, ext)
|
|
finalPath = filepath.Join(baseDir, newName)
|
|
if _, err := os.Stat(finalPath); os.IsNotExist(err) {
|
|
return newName
|
|
}
|
|
}
|
|
}
|
|
|
|
// resolveSafe safely resolves a requested path against a root directory,
|
|
// ensuring the result is completely contained within the root.
|
|
// Returns the absolute clean path or an error if traversal is detected.
|
|
func resolveSafe(rootDir, reqPath string) (string, error) {
|
|
cleanRoot := filepath.Clean(rootDir)
|
|
|
|
// Pre-check for typical traversal patterns to be safe
|
|
cleanReq := filepath.Clean(filepath.FromSlash(reqPath))
|
|
if strings.HasPrefix(cleanReq, "..") || strings.HasPrefix(cleanReq, "/") || strings.HasPrefix(cleanReq, "\\") {
|
|
return "", fmt.Errorf("invalid path: contains traversal patterns")
|
|
}
|
|
|
|
absPath := filepath.Join(cleanRoot, cleanReq)
|
|
|
|
// Ensure the resulting path starts with the root directory + separator
|
|
// (or is exactly the root directory)
|
|
if !strings.HasPrefix(absPath, cleanRoot+string(filepath.Separator)) && absPath != cleanRoot {
|
|
return "", fmt.Errorf("path traversal attempt detected")
|
|
}
|
|
|
|
return absPath, nil
|
|
}
|