30 lines
871 B
Go
30 lines
871 B
Go
|
package storage
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// Get the first file path component. We can't use filepath.Split because that breaks off the last
|
||
|
// one. We could optimize this to avoid allocating a slice down the track.
|
||
|
func firstComponent(filePath string) string {
|
||
|
return strings.SplitN(filePath, string(filepath.Separator), 2)[0]
|
||
|
}
|
||
|
|
||
|
// Combines file info path components, ensuring the result won't escape into parent directories.
|
||
|
func ToSafeFilePath(fileInfoComponents ...string) (string, error) {
|
||
|
safeComps := make([]string, 0, len(fileInfoComponents))
|
||
|
for _, comp := range fileInfoComponents {
|
||
|
safeComps = append(safeComps, filepath.Clean(comp))
|
||
|
}
|
||
|
safeFilePath := filepath.Join(safeComps...)
|
||
|
fc := firstComponent(safeFilePath)
|
||
|
switch fc {
|
||
|
case "..":
|
||
|
return "", errors.New("escapes root dir")
|
||
|
default:
|
||
|
return safeFilePath, nil
|
||
|
}
|
||
|
}
|