mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
72 lines
2.1 KiB
Go
72 lines
2.1 KiB
Go
package pathutil
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// SafePath validates and constructs a safe file path within a base directory.
|
|
// Returns an error if the resulting path would escape the base directory.
|
|
func SafePath(baseDir, filename string) (string, error) {
|
|
// Reject absolute paths in filename
|
|
if filepath.IsAbs(filename) {
|
|
return "", fmt.Errorf("invalid filename: absolute paths not allowed")
|
|
}
|
|
|
|
// Reject any path containing ".." before cleaning (catches obvious attacks)
|
|
if strings.Contains(filename, "..") {
|
|
return "", fmt.Errorf("invalid filename: path traversal not allowed")
|
|
}
|
|
|
|
// Clean the filename
|
|
cleanFilename := filepath.Clean(filename)
|
|
|
|
// After cleaning, reject if ".." appears (handles edge cases)
|
|
if strings.Contains(cleanFilename, "..") {
|
|
return "", fmt.Errorf("invalid filename: path traversal not allowed")
|
|
}
|
|
|
|
// Get absolute base directory path
|
|
absBase, err := filepath.Abs(baseDir)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get absolute path for base directory: %w", err)
|
|
}
|
|
|
|
// Construct and resolve the full path
|
|
fullPath := filepath.Join(absBase, cleanFilename)
|
|
|
|
absPath, err := filepath.Abs(fullPath)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get absolute path: %w", err)
|
|
}
|
|
|
|
// Ensure the resolved path is within the base directory
|
|
// Add trailing separator to absBase to prevent prefix matching issues
|
|
// (e.g., /foo/bar matching /foo/barbaz)
|
|
basePrefixCheck := absBase
|
|
if !strings.HasSuffix(basePrefixCheck, string(filepath.Separator)) {
|
|
basePrefixCheck += string(filepath.Separator)
|
|
}
|
|
|
|
// The path is safe if it equals absBase or starts with absBase + separator
|
|
if absPath != absBase && !strings.HasPrefix(absPath, basePrefixCheck) {
|
|
return "", fmt.Errorf("path outside base directory not allowed")
|
|
}
|
|
|
|
return fullPath, nil
|
|
}
|
|
|
|
// ValidateFilePath validates a file path for security concerns
|
|
func ValidateFilePath(filePath string) error {
|
|
// Clean the path
|
|
cleanPath := filepath.Clean(filePath)
|
|
|
|
// Check for path traversal attempts
|
|
if strings.Contains(cleanPath, "..") {
|
|
return fmt.Errorf("invalid file path: path traversal not allowed")
|
|
}
|
|
|
|
return nil
|
|
}
|