49 lines
1.4 KiB
Go
49 lines
1.4 KiB
Go
package storage
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
)
|
|
|
|
const tagStorage = "Storage"
|
|
|
|
var (
|
|
readErrors = []int{401, 403, 500}
|
|
writeErrors = []int{400, 401, 403, 409, 500}
|
|
)
|
|
|
|
// Validation regexes. Every value is also passed after "--" on the command line.
|
|
// We forbid whitespace and shell metacharacters outright (mount/umount take no
|
|
// such values for our purposes, and fstab fields with spaces would need octal
|
|
// escaping we don't emit).
|
|
var (
|
|
// deviceRe allows a /dev path or a UUID=/LABEL= specifier.
|
|
deviceRe = regexp.MustCompile(`^(/dev/[a-zA-Z0-9/._-]+|UUID=[a-zA-Z0-9-]+|LABEL=[a-zA-Z0-9._-]+|PARTUUID=[a-zA-Z0-9-]+)$`)
|
|
// mountpointRe is an absolute path without traversal or whitespace.
|
|
mountpointRe = regexp.MustCompile(`^/[a-zA-Z0-9/._-]*$`)
|
|
// fstypeRe matches a filesystem type token (ext4, xfs, btrfs, vfat, nfs, …).
|
|
fstypeRe = regexp.MustCompile(`^[a-z0-9]+$`)
|
|
// optionsRe matches a comma-separated mount option list (defaults, noatime,
|
|
// uid=1000, …).
|
|
optionsRe = regexp.MustCompile(`^[a-zA-Z0-9=,._:+-]+$`)
|
|
)
|
|
|
|
func validateMountpoint(mp string) error {
|
|
if !mountpointRe.MatchString(mp) || hasDotDot(mp) {
|
|
return huma.Error400BadRequest("invalid mountpoint: " + mp)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// hasDotDot rejects a ".." path segment so a mountpoint can't escape upward.
|
|
func hasDotDot(p string) bool {
|
|
for _, seg := range strings.Split(p, "/") {
|
|
if seg == ".." {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|