61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// sanitizePath encodes invalid filesystem characters using URL encoding.
|
|
// Example:
|
|
// /example/path/to/page?query=param&another=value
|
|
// would become
|
|
// example/path/to/page%3Fquery%3Dparam%26another%3Dvalue
|
|
func sanitizePath(p string) string {
|
|
// Split the path into its components
|
|
components := strings.Split(p, "/")
|
|
|
|
// Encode each component separately
|
|
for i, component := range components {
|
|
// Decode any existing percent-encoded characters
|
|
decodedComponent, err := url.PathUnescape(component)
|
|
if err != nil {
|
|
decodedComponent = component // Fallback to original if unescape fails
|
|
}
|
|
|
|
// Encode the component to escape invalid filesystem characters
|
|
encodedComponent := url.QueryEscape(decodedComponent)
|
|
|
|
// Replace '+' (from QueryEscape) with '%20' to handle spaces correctly
|
|
encodedComponent = strings.ReplaceAll(encodedComponent, "+", "%20")
|
|
|
|
components[i] = encodedComponent
|
|
}
|
|
|
|
// Rejoin the components into a sanitized path
|
|
safe := filepath.Join(components...)
|
|
|
|
return safe
|
|
}
|
|
|
|
// getFilePath constructs a safe file path from the root path and URL path.
|
|
// It URL-encodes invalid filesystem characters to ensure the path is valid.
|
|
func calcFilePath(rootPath, urlPath string) (string, error) {
|
|
// Normalize the URL path
|
|
cleanPath := filepath.Clean(urlPath)
|
|
|
|
// Safe check to prevent directory traversal
|
|
if strings.Contains(cleanPath, "..") {
|
|
return "", fmt.Errorf("Invalid URL path: contains directory traversal")
|
|
}
|
|
|
|
// Sanitize the path by encoding invalid characters
|
|
safePath := sanitizePath(cleanPath)
|
|
|
|
// Join the root path and the sanitized URL path
|
|
finalPath := filepath.Join(rootPath, safePath)
|
|
|
|
return finalPath, nil
|
|
}
|