chromium/chrome/browser/ash/smb_client/smbfs_share.h

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_SMB_CLIENT_SMBFS_SHARE_H_
#define CHROME_BROWSER_ASH_SMB_CLIENT_SMBFS_SHARE_H_

#include <memory>
#include <string>

#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/smb_client/smb_errors.h"
#include "chrome/browser/ash/smb_client/smb_url.h"
#include "chromeos/ash/components/smbfs/smbfs_host.h"
#include "chromeos/ash/components/smbfs/smbfs_mounter.h"

class Profile;

namespace ash::smb_client {

// Represents an SMB share mounted using smbfs. Handles mounting, unmounting,
// registration, and IPC communication with filesystem.
// Destroying will unmount and deregister the filesystem.
class SmbFsShare : public smbfs::SmbFsHost::Delegate {
 public:
  using KerberosOptions = smbfs::SmbFsMounter::KerberosOptions;
  using MountOptions = smbfs::SmbFsMounter::MountOptions;
  using MountCallback = base::OnceCallback<void(SmbMountResult)>;
  using UnmountCallback = base::OnceCallback<void(MountError)>;
  using RemoveCredentialsCallback = base::OnceCallback<void(bool)>;
  using DeleteRecursivelyCallback = base::OnceCallback<void(base::File::Error)>;
  using MounterCreationCallback =
      base::RepeatingCallback<std::unique_ptr<smbfs::SmbFsMounter>(
          const std::string& share_path,
          const std::string& mount_dir_name,
          const MountOptions& options,
          smbfs::SmbFsHost::Delegate* delegate)>;

  SmbFsShare(Profile* profile,
             const SmbUrl& share_url,
             const std::string& display_name,
             const MountOptions& options);
  ~SmbFsShare() override;

  SmbFsShare(const SmbFsShare&) = delete;
  SmbFsShare& operator=(const SmbFsShare&) = delete;

  // Mounts the SMB filesystem with |options_| and runs |callback| when
  // completed. Must not be called while mounted or another mount request is in
  // progress.
  void Mount(MountCallback callback);

  // Remount an unmounted SMB filesystem with |options| and run |callback|
  // when completed. |options_| will be updated by |options|.
  void Remount(const MountOptions& options, MountCallback callback);

  // Unmounts the filesystem and cancels any pending mount request.
  void Unmount(UnmountCallback callback);

  // Allow smbfs to make credentials request for a short period of time
  // (currently 5 seconds).
  void AllowCredentialsRequest();

  // Request that any credentials saved by smbfs are deleted.
  void RemoveSavedCredentials(RemoveCredentialsCallback callback);

  // Recursively delete |path| by making a Mojo request to smbfs.
  void DeleteRecursively(const base::FilePath& path,
                         DeleteRecursivelyCallback callback);

  // Returns whether the filesystem is mounted and accessible via mount_path().
  bool IsMounted() const { return bool(host_); }

  const std::string& mount_id() const { return mount_id_; }
  const SmbUrl& share_url() const { return share_url_; }
  const MountOptions& options() const { return options_; }

  base::FilePath mount_path() const {
    return host_ ? host_->mount_path() : base::FilePath();
  }

  void SetMounterCreationCallbackForTest(MounterCreationCallback callback);

 private:
  FRIEND_TEST_ALL_PREFIXES(SmbFsShareTest, GenerateStableMountId);
  FRIEND_TEST_ALL_PREFIXES(SmbFsShareTest, GenerateStableMountIdInput);

  // Callback for smbfs::SmbFsMounter::Mount().
  void OnMountDone(MountCallback callback,
                   smbfs::mojom::MountError mount_error,
                   std::unique_ptr<smbfs::SmbFsHost> smbfs_host);

  // Called after cros-disks has attempted to unmount the share.
  void OnUnmountDone(SmbFsShare::UnmountCallback callback, MountError result);

  // Callback for smb_dialog::SmbCredentialsDialog::Show().
  void OnSmbCredentialsDialogShowDone(RequestCredentialsCallback callback,
                                      bool canceled,
                                      const std::string& username,
                                      const std::string& password);

  // Callback for smbfs::SmbFsHost::RemoveSavedCredentials().
  void OnRemoveSavedCredentialsDone(bool success);

  // Callback for smbfs::SmbFsHost::DeleteRecursively().
  void OnDeleteRecursivelyDone(base::File::Error error);

  // smbfs::SmbFsHost::Delegate overrides:
  void OnDisconnected() override;
  void RequestCredentials(RequestCredentialsCallback callback) override;

  // Generate a stable ID to uniquely identify the share across each
  // mount / unmount cycle. This allows the share to have the same path
  // on the filesystem each time it is mounted.
  //
  // This function creates uniqueness beyond that currently enforced by
  // the system (which presently only allows one share per canonical URL
  // to be mounted). IDs generated here will be forward compatible in a
  // future where the same share could be mounted once (ie. read-only)
  // by preconfigured policy and subsequently by the user but using
  // read-write credentials).
  std::string GenerateStableMountId() const;

  // Generate the input for stable mount ID hash (simplifies testing).
  std::string GenerateStableMountIdInput() const;

  const raw_ptr<Profile> profile_;
  const SmbUrl share_url_;
  const std::string display_name_;
  MountOptions options_;
  const std::string mount_id_;
  bool unmount_pending_ = false;
  RemoveCredentialsCallback remove_credentials_callback_;
  DeleteRecursivelyCallback delete_recursively_callback_;

  MounterCreationCallback mounter_creation_callback_for_test_;
  std::unique_ptr<smbfs::SmbFsMounter> mounter_;
  std::unique_ptr<smbfs::SmbFsHost> host_;

  base::TimeTicks allow_credential_request_expiry_;
  bool allow_credential_request_ = false;

  base::WeakPtrFactory<SmbFsShare> weak_factory_{this};
};

}  // namespace ash::smb_client

#endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMBFS_SHARE_H_