package files import ( "context" "errors" "fmt" "os" "path/filepath" "strings" ) var ( ErrUnsafeInstanceDataDirectory = errors.New("unsafe instance data directory") ErrInstanceDataNotDirectory = errors.New("instance data path is not a directory") ) // InstanceDataRemover deletes one explicitly authorized browser User Data Dir. // Callers must check browser occupancy before invoking it. type InstanceDataRemover interface { RemoveInstanceData(context.Context, string) error } type instanceDataRemover struct { lstat func(string) (os.FileInfo, error) removeAll func(string) error } func NewInstanceDataRemover() InstanceDataRemover { return newInstanceDataRemover(os.Lstat, os.RemoveAll) } func newInstanceDataRemover(lstat func(string) (os.FileInfo, error), removeAll func(string) error) instanceDataRemover { return instanceDataRemover{lstat: lstat, removeAll: removeAll} } func (r instanceDataRemover) RemoveInstanceData(ctx context.Context, userDataDir string) error { if err := ctx.Err(); err != nil { return err } path, err := normalizeRemovableInstanceDataDir(userDataDir) if err != nil { return err } info, err := r.lstat(path) if errors.Is(err, os.ErrNotExist) { return nil } if err != nil { return fmt.Errorf("inspect instance data directory: %w", err) } if info.Mode()&(os.ModeSymlink|os.ModeIrregular) != 0 || isReparsePoint(info) { return fmt.Errorf("%w: links and reparse points are not removable", ErrUnsafeInstanceDataDirectory) } if !info.IsDir() { return ErrInstanceDataNotDirectory } if err := ctx.Err(); err != nil { return err } if err := r.removeAll(path); err != nil { return fmt.Errorf("remove instance data directory: %w", err) } return nil } func normalizeRemovableInstanceDataDir(value string) (string, error) { value = strings.TrimSpace(value) if value == "" || !filepath.IsAbs(value) { return "", fmt.Errorf("%w: path must be absolute", ErrUnsafeInstanceDataDirectory) } path := filepath.Clean(value) volumeRoot := filepath.Clean(filepath.VolumeName(path) + string(filepath.Separator)) if strings.EqualFold(path, volumeRoot) { return "", fmt.Errorf("%w: volume root is not removable", ErrUnsafeInstanceDataDirectory) } return path, nil }