chromium/chrome/browser/chromeos/policy/dlp/dlp_download_observer_unittest.cc

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

#include "chrome/browser/chromeos/policy/dlp/dlp_download_observer.h"

#include <memory>

#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chromeos/dbus/dlp/dlp_client.h"
#include "chromeos/dbus/dlp/dlp_service.pb.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_save_item_data.h"
#include "components/download/public/common/mock_download_item.h"
#include "components/file_access/scoped_file_access.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace policy {

using testing::_;

namespace {
constexpr char kFilePath[] = "/path/to/file";
constexpr char kTabUrl[] = "https://example.com/tab";
constexpr char kDataUrl[] = "data:text/plain;charset=UTF-8,test";
constexpr char kHttpsUrl[] = "https://example.com/https";
constexpr char kReferrerUrl[] = "https://referrer.example.com";
constexpr char kBlobUrl[] = "blob:https://example.com/uuid";
constexpr char kOriginUrl[] = "https://example.com/";
}  // namespace

class DlpDownloadObserverTest : public testing::Test {
 public:
  void SetUp() override { chromeos::DlpClient::Get()->InitializeFake(); }
  void TearDown() override { chromeos::DlpClient::Get()->Shutdown(); }
};

// Tests if we correctly request dlp file access for a data: url with the tab
// url.
TEST_F(DlpDownloadObserverTest, TestDataSchemeRewrite) {
  base::MockRepeatingCallback<void(const dlp::AddFilesRequest,
                                   chromeos::DlpClient::AddFilesCallback)>
      add_files_cb;
  EXPECT_CALL(
      add_files_cb,
      Run(testing::Property(&dlp::AddFilesRequest::add_file_requests,
                            testing::ElementsAre(testing::Property(
                                &dlp::AddFileRequest::source_url, kTabUrl))),
          _))
      .WillOnce(base::test::RunOnceCallback<1>(
          dlp::AddFilesResponse::default_instance()));
  auto* dlp_client = chromeos::DlpClient::Get()->GetTestInterface();
  dlp_client->SetAddFilesMock(add_files_cb.Get());

  auto key = SimpleFactoryKey(base::FilePath(), false);
  DlpDownloadObserver observer(&key);
  testing::NiceMock<download::MockDownloadItem> item;
  base::FilePath file_path(kFilePath);
  GURL data_url(kDataUrl);
  GURL referrer_url(kReferrerUrl);
  GURL tab_url(kTabUrl);

  ON_CALL(item, IsSavePackageDownload).WillByDefault(testing::Return(false));
  ON_CALL(item, GetState)
      .WillByDefault(
          testing::Return(download::DownloadItem::DownloadState::COMPLETE));
  ON_CALL(item, GetFullPath).WillByDefault(testing::ReturnRef(file_path));
  ON_CALL(item, GetURL).WillByDefault(testing::ReturnRef(data_url));
  ON_CALL(item, GetReferrerUrl).WillByDefault(testing::ReturnRef(referrer_url));
  ON_CALL(item, GetTabUrl).WillByDefault(testing::ReturnRef(tab_url));

  observer.OnDownloadUpdated(&item);
}

// Test if we request file access with the original url in the default case.
TEST_F(DlpDownloadObserverTest, TestNoSchemeRewrite) {
  base::MockRepeatingCallback<void(const dlp::AddFilesRequest,
                                   chromeos::DlpClient::AddFilesCallback)>
      add_files_cb;
  EXPECT_CALL(
      add_files_cb,
      Run(testing::Property(&dlp::AddFilesRequest::add_file_requests,
                            testing::ElementsAre(testing::Property(
                                &dlp::AddFileRequest::source_url, kHttpsUrl))),
          _))
      .WillOnce(base::test::RunOnceCallback<1>(
          dlp::AddFilesResponse::default_instance()));
  auto* dlp_client = chromeos::DlpClient::Get()->GetTestInterface();
  dlp_client->SetAddFilesMock(add_files_cb.Get());

  auto key = SimpleFactoryKey(base::FilePath(), false);
  DlpDownloadObserver observer(&key);
  testing::NiceMock<download::MockDownloadItem> item;
  base::FilePath file_path(kFilePath);
  GURL https_url(kHttpsUrl);
  GURL referrer_url(kReferrerUrl);
  GURL tab_url(kTabUrl);

  ON_CALL(item, IsSavePackageDownload).WillByDefault(testing::Return(false));
  ON_CALL(item, GetState)
      .WillByDefault(
          testing::Return(download::DownloadItem::DownloadState::COMPLETE));
  ON_CALL(item, GetFullPath).WillByDefault(testing::ReturnRef(file_path));
  ON_CALL(item, GetURL).WillByDefault(testing::ReturnRef(https_url));
  ON_CALL(item, GetReferrerUrl).WillByDefault(testing::ReturnRef(referrer_url));
  ON_CALL(item, GetTabUrl).WillByDefault(testing::ReturnRef(tab_url));
  observer.OnDownloadUpdated(&item);
}

// Test if we request the file access for a blob: url with its origin. We do
// this as the url matcher would not recognize the host in the blob: url.
TEST_F(DlpDownloadObserverTest, TestBlobSchemeRewrite) {
  base::MockRepeatingCallback<void(const dlp::AddFilesRequest,
                                   chromeos::DlpClient::AddFilesCallback)>
      add_files_cb;
  EXPECT_CALL(
      add_files_cb,
      Run(testing::Property(&dlp::AddFilesRequest::add_file_requests,
                            testing::ElementsAre(testing::Property(
                                &dlp::AddFileRequest::source_url, kOriginUrl))),
          _))
      .WillOnce(base::test::RunOnceCallback<1>(
          dlp::AddFilesResponse::default_instance()));
  auto* dlp_client = chromeos::DlpClient::Get()->GetTestInterface();
  dlp_client->SetAddFilesMock(add_files_cb.Get());

  auto key = SimpleFactoryKey(base::FilePath(), false);
  DlpDownloadObserver observer(&key);
  testing::NiceMock<download::MockDownloadItem> item;
  base::FilePath file_path(kFilePath);
  GURL blob_url(kBlobUrl);
  GURL referrer_url(kReferrerUrl);
  GURL tab_url(kTabUrl);

  ON_CALL(item, IsSavePackageDownload).WillByDefault(testing::Return(false));
  ON_CALL(item, GetState)
      .WillByDefault(
          testing::Return(download::DownloadItem::DownloadState::COMPLETE));
  ON_CALL(item, GetFullPath).WillByDefault(testing::ReturnRef(file_path));
  ON_CALL(item, GetURL).WillByDefault(testing::ReturnRef(blob_url));
  ON_CALL(item, GetReferrerUrl).WillByDefault(testing::ReturnRef(referrer_url));
  ON_CALL(item, GetTabUrl).WillByDefault(testing::ReturnRef(tab_url));

  observer.OnDownloadUpdated(&item);
}

// Test if we request the file access for a data: url, while the tab is a blob:
// url, the origin of the tab is used as source.
TEST_F(DlpDownloadObserverTest, TestDataSchemeInBlobTabRewrite) {
  base::MockRepeatingCallback<void(const dlp::AddFilesRequest,
                                   chromeos::DlpClient::AddFilesCallback)>
      add_files_cb;
  EXPECT_CALL(
      add_files_cb,
      Run(testing::Property(&dlp::AddFilesRequest::add_file_requests,
                            testing::ElementsAre(testing::Property(
                                &dlp::AddFileRequest::source_url, kOriginUrl))),
          _))
      .WillOnce(base::test::RunOnceCallback<1>(
          dlp::AddFilesResponse::default_instance()));
  auto* dlp_client = chromeos::DlpClient::Get()->GetTestInterface();
  dlp_client->SetAddFilesMock(add_files_cb.Get());

  auto key = SimpleFactoryKey(base::FilePath(), false);
  DlpDownloadObserver observer(&key);
  testing::NiceMock<download::MockDownloadItem> item;
  base::FilePath file_path(kFilePath);
  GURL blob_url(kBlobUrl);
  GURL referrer_url(kReferrerUrl);
  GURL data_url(kDataUrl);

  ON_CALL(item, IsSavePackageDownload).WillByDefault(testing::Return(false));
  ON_CALL(item, GetState)
      .WillByDefault(
          testing::Return(download::DownloadItem::DownloadState::COMPLETE));
  ON_CALL(item, GetFullPath).WillByDefault(testing::ReturnRef(file_path));
  ON_CALL(item, GetURL).WillByDefault(testing::ReturnRef(data_url));
  ON_CALL(item, GetReferrerUrl).WillByDefault(testing::ReturnRef(referrer_url));
  ON_CALL(item, GetTabUrl).WillByDefault(testing::ReturnRef(blob_url));

  observer.OnDownloadUpdated(&item);
}

}  // namespace policy