package storage import ( "errors" "path" "strings" ) // normalizeDeletePrefix rejects requests that could accidentally target the // storage root and returns the canonical key form used by all backends. func normalizeDeletePrefix(prefix string) (string, error) { prefix = strings.TrimSpace(strings.ReplaceAll(prefix, "\\", "/")) prefix = strings.Trim(prefix, "/") if prefix == "" { return "", errors.New("storage delete prefix is required") } for _, part := range strings.Split(prefix, "/") { if part == ".." { return "", errors.New("invalid storage delete prefix") } } clean := path.Clean(prefix) if clean == "." || clean == ".." || strings.HasPrefix(clean, "../") { return "", errors.New("invalid storage delete prefix") } return clean, nil } // advanceDeletePrefixCursor prevents a backend that reports a truncated page // without a new cursor from making DeletePrefix loop forever. func advanceDeletePrefixCursor(current, next string, more bool) (string, error) { if !more { return "", nil } current = strings.TrimSpace(current) next = strings.TrimSpace(next) if next == "" || next == current { return "", errors.New("storage delete prefix pagination made no progress") } return next, nil }