chromium/chrome/browser/ash/file_manager/copy_or_move_io_task_policy_impl.h

// Copyright 2022 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_FILE_MANAGER_COPY_OR_MOVE_IO_TASK_POLICY_IMPL_H_
#define CHROME_BROWSER_ASH_FILE_MANAGER_COPY_OR_MOVE_IO_TASK_POLICY_IMPL_H_

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/file_manager/copy_or_move_io_task_impl.h"
#include "chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.h"
#include "chrome/browser/enterprise/connectors/analysis/file_transfer_analysis_delegate.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h"

namespace enterprise_connectors {
class FileTransferAnalysisDelegate;
}  // namespace enterprise_connectors

namespace file_manager::io_task {

// This class represents a copy or move operation with enabled scanning through
// the OnFileTransferEnterpriseConnector policy.
// This class performs enterprise connector checks for each source file system
// url.
//
// For `settings.block_until_verdict == kBlock`, scans are performed before the
// copy/move operation is started. The scanning results are then used during the
// transfer to block specific files, i.e., when they contain malware or
// sensitive data.
//
// For `settings.block_until_verdict == kNoBlock`, scans are performed after the
// copy/move operation has completed and the results are only used for
// reporting. This is done to minimize the influence of the scan to the user
// experience. As the source might no longer exist after the scan, e.g., because
// the operation was a move, the files are scanned at the destination.
class CopyOrMoveIOTaskPolicyImpl : public CopyOrMoveIOTaskImpl {
  using IsTransferAllowedCallback = base::OnceCallback<void(base::File::Error)>;

 public:
  // `type` must be either kCopy or kMove. The size of `source_urls` and
  // `destination_file_names` must be the same. `settings` should be the
  // settings returned by `FileTransferAnalysisDelegate::IsEnabledVec()` and
  // contain separate settings for each source url. A setting for a source url
  // can be null if scanning is not enabled for that source url.
  CopyOrMoveIOTaskPolicyImpl(
      OperationType type,
      ProgressStatus& progress,
      std::vector<base::FilePath> destination_file_names,
      std::vector<std::optional<enterprise_connectors::AnalysisSettings>>
          settings,
      storage::FileSystemURL destination_folder,
      Profile* profile,
      scoped_refptr<storage::FileSystemContext> file_system_context,
      bool show_notification = true);
  ~CopyOrMoveIOTaskPolicyImpl() override;

  // CopyOrMoveIOTaskImpl overrides:
  void Execute(ProgressCallback progress_callback,
               CompleteCallback complete_callback) override;
  void Resume(ResumeParams params) override;
  void Complete(State state) override;

 private:
  // CopyOrMoveIOTaskImpl overrides:
  // Verifies the transfer by applying Data Leak Prevention files restrictions
  // and enterprise connectors scans.
  void VerifyTransfer() override;
  storage::FileSystemOperation::ErrorBehavior GetErrorBehavior() override;
  std::unique_ptr<storage::CopyOrMoveHookDelegate> GetHookDelegate(
      size_t idx) override;

  // This function scans the source associated with `idx` if scanning is enabled
  // for the respective source-destination-pair.
  // Scanning is always disabled if the source and destination reside on the
  // same volume.
  // For scanning to be enabled, the OnFileTransferEnterpriseConnector policy
  // has to match the source-destination-pair.
  // Scanning is performed recursively for all files within
  // `progress_.sources[idx]`.
  void MaybeScanForDisallowedFiles(size_t idx);

  // Called when scanning is completed.
  void ScanningCompleted();

  // Shows a warning for the connectors.
  // Returns whether the warning was shown.
  bool MaybeShowConnectorsWarning();

  // Called after the warning dialog is proceeded or cancelled.
  // This resumes the transfer and allows for the warned files to be transferred
  // if the warning is proceeded.
  void OnConnectorsWarnDialogResult(
      std::optional<std::u16string> user_justification,
      bool should_proceed);

  // Checks `file_transfer_analysis_delegates_[idx]` whether a transfer is
  // allowed for the source-destination-pair.
  // If it is allowed, callback will be called with `base::File::FILE_OK`.
  // Otherwise, the callback is run with `base::File::FILE_ERROR_SECURITY`.
  // Note: This function is only allowed to be called if scanning was performed
  // for `idx`.
  void IsTransferAllowed(size_t idx,
                         const storage::FileSystemURL& source_url,
                         const storage::FileSystemURL& destination_url,
                         IsTransferAllowedCallback callback);

  // Continues executing the IO task after DLP checks are done.
  void OnCheckIfTransferAllowed(
      std::vector<storage::FileSystemURL> blocked_entries);

  // Returns the total number of files in `connectors_blocked_files_`.
  size_t GetConnectorsBlockedFilesNum() const;

  raw_ptr<Profile> profile_;
  scoped_refptr<storage::FileSystemContext> file_system_context_;

  // Stores the settings, only valid until creation of respective.
  // FileTransferAnalysisDelegate.
  std::vector<std::optional<enterprise_connectors::AnalysisSettings>> settings_;
  // Stores the delegates responsible for the file scanning.
  // Will be empty if the FileTransferConnector is disabled. If scanning is
  // disabled for a source-destination-pair, the unique_ptr will be nullptr. If
  // scanning is enabled, a FileTransferAnalysisDelegate will be created.
  std::vector<
      std::unique_ptr<enterprise_connectors::FileTransferAnalysisDelegate>>
      file_transfer_analysis_delegates_;

  // Specifies whether scanning should be used only for reporting.
  // This is set to true if `block_until_verdict` is 0.
  bool report_only_scans_ = false;

  // The list of files blocked by Data Leak Prevention policy.
  std::set<base::FilePath> dlp_blocked_files_;

  // Maps block reasons to their associated enterprise connector blocked file
  // paths.
  std::map<policy::FilesPolicyDialog::BlockReason, std::vector<base::FilePath>>
      connectors_blocked_files_;

  base::WeakPtrFactory<CopyOrMoveIOTaskPolicyImpl> weak_ptr_factory_{this};
};

}  // namespace file_manager::io_task

#endif  // CHROME_BROWSER_ASH_FILE_MANAGER_COPY_OR_MOVE_IO_TASK_POLICY_IMPL_H_