30 lines
760 B
Go
30 lines
760 B
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// resolveSafe joins p onto root, cleans it, and confirms the result stays
|
|
// within root. Rejects absolute paths and anything that escapes via "..".
|
|
func resolveSafe(root, p string) (string, error) {
|
|
if p == "" {
|
|
return "", fmt.Errorf("empty path")
|
|
}
|
|
if filepath.IsAbs(p) {
|
|
return "", fmt.Errorf("absolute paths are not allowed: %s", p)
|
|
}
|
|
joined := filepath.Join(root, p)
|
|
cleaned := filepath.Clean(joined)
|
|
|
|
rel, err := filepath.Rel(root, cleaned)
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot resolve %q: %w", p, err)
|
|
}
|
|
if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
|
|
return "", fmt.Errorf("path escapes project root: %s", p)
|
|
}
|
|
return cleaned, nil
|
|
}
|