#include "ui/base/clipboard/clipboard.h"
#include <memory>
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/test_future.h"
#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog.h"
#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog_test_helper.h"
#include "chrome/browser/printing/print_preview_dialog_controller.h"
#include "chrome/browser/printing/print_test_utils.h"
#include "chrome/browser/printing/test_print_preview_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/enterprise/data_controls/core/browser/features.h"
#include "components/enterprise/data_controls/core/browser/test_utils.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/permissions_test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "printing/buildflags/buildflags.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/clipboard/test/test_clipboard.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/views/test/widget_activation_waiter.h"
namespace enterprise_data_protection {
namespace {
class DataProtectionClipboardBrowserTest : public InProcessBrowserTest {
public:
DataProtectionClipboardBrowserTest() = default;
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
ui::TestClipboard::CreateForCurrentThread();
}
void TearDownOnMainThread() override {
ui::TestClipboard::DestroyClipboardForCurrentThread();
InProcessBrowserTest::TearDownOnMainThread();
}
content::RenderFrameHost* rfh() {
return browser()
->tab_strip_model()
->GetActiveWebContents()
->GetPrimaryMainFrame();
}
GURL url() {
return embedded_test_server()->GetURL(
"/enterprise/data_protection/clipboard_test_page.html");
}
void FocusWebContents(content::WebContents* web_contents = nullptr) {
#if BUILDFLAG(IS_MAC)
content::HandleMissingKeyWindow();
#endif
if (!web_contents) {
web_contents = browser()->tab_strip_model()->GetActiveWebContents();
}
web_contents->Focus();
views::test::WaitForWidgetActive(
BrowserView::GetBrowserViewForBrowser(browser())->GetWidget(), true);
}
void WriteTextToClipboard(const std::string& text,
content::WebContents* web_contents = nullptr) {
ui::Clipboard::GetForCurrentThread()->Clear(
ui::ClipboardBuffer::kCopyPaste);
FocusWebContents(web_contents);
ASSERT_TRUE(content::ExecJs(
web_contents ? web_contents->GetPrimaryMainFrame() : rfh(),
base::StringPrintf("navigator.clipboard.writeText(\"%s\");",
text.c_str())));
base::RunLoop().RunUntilIdle();
}
void SetTextInClipboardAndWritePermission(const std::u16string& text) {
{
ui::ScopedClipboardWriter writer(ui::ClipboardBuffer::kCopyPaste);
writer.WriteText(text);
}
base::RunLoop().RunUntilIdle();
content::PermissionController* permission_controller =
rfh()->GetBrowserContext()->GetPermissionController();
url::Origin origin = url::Origin::Create(url());
SetPermissionControllerOverride(permission_controller, origin, origin,
blink::PermissionType::CLIPBOARD_READ_WRITE,
blink::mojom::PermissionStatus::GRANTED);
base::RunLoop().RunUntilIdle();
}
};
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
CopyBlockedByDataControls) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"sources": { "urls": ["*"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "BLOCK"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardCopyBlock);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
WriteTextToClipboard("Blocked");
helper.WaitForDialogToInitialize();
base::test::TestFuture<std::u16string> first_future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
first_future.GetCallback());
EXPECT_TRUE(first_future.Wait());
EXPECT_TRUE(first_future.Get().empty());
helper.CloseDialogWithoutBypass();
helper.WaitForDialogToClose();
base::test::TestFuture<std::u16string> second_future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
second_future.GetCallback());
EXPECT_TRUE(second_future.Wait());
EXPECT_TRUE(second_future.Get().empty());
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
CopyWarnedByDataControls_Cancel) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"sources": { "urls": ["*"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "WARN"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardCopyWarn);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
WriteTextToClipboard("Cancel");
helper.WaitForDialogToInitialize();
base::test::TestFuture<std::u16string> first_future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
first_future.GetCallback());
EXPECT_TRUE(first_future.Wait());
EXPECT_TRUE(first_future.Get().empty());
helper.CloseDialogWithoutBypass();
helper.WaitForDialogToClose();
base::test::TestFuture<std::u16string> second_future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
second_future.GetCallback());
EXPECT_TRUE(second_future.Wait());
EXPECT_TRUE(second_future.Get().empty());
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
CopyWarnedByDataControls_Bypass) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"sources": { "urls": ["*"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "WARN"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardCopyWarn);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
WriteTextToClipboard("Bypassed");
helper.WaitForDialogToInitialize();
base::test::TestFuture<std::u16string> first_future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
first_future.GetCallback());
EXPECT_TRUE(first_future.Wait());
EXPECT_TRUE(first_future.Get().empty());
helper.BypassWarning();
helper.WaitForDialogToClose();
base::RunLoop().RunUntilIdle();
base::test::TestFuture<std::u16string> second_future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
second_future.GetCallback());
EXPECT_TRUE(second_future.Wait());
EXPECT_EQ(second_future.Get(), u"Bypassed");
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
CopyAllowedByDataControls) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"sources": { "urls": ["google.com"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "WARN"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardCopyWarn);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
WriteTextToClipboard("Allowed");
ASSERT_FALSE(helper.dialog());
base::test::TestFuture<std::u16string> future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
future.GetCallback());
EXPECT_TRUE(future.Wait());
EXPECT_EQ(future.Get(), u"Allowed");
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
PasteBlockedByDataControls) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"destinations": { "urls": ["*"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "BLOCK"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
SetTextInClipboardAndWritePermission(u"Blocked");
FocusWebContents();
content::ExecuteScriptAsync(
rfh(), R"(var pasted_text = navigator.clipboard.readText();)");
helper.WaitForDialogToInitialize();
helper.CloseDialogWithoutBypass();
helper.WaitForDialogToClose();
EXPECT_EQ(content::EvalJs(rfh(), "pasted_text"), "");
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
PasteWarnedByDataControls_Cancel) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"destinations": { "urls": ["*"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "WARN"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardPasteWarn);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
SetTextInClipboardAndWritePermission(u"Warned_Cancel");
FocusWebContents();
content::ExecuteScriptAsync(
rfh(), R"(var pasted_text = navigator.clipboard.readText();)");
helper.WaitForDialogToInitialize();
helper.CloseDialogWithoutBypass();
helper.WaitForDialogToClose();
EXPECT_EQ(content::EvalJs(rfh(), "pasted_text"), "");
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
PasteWarnedByDataControls_Bypass) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"destinations": { "urls": ["*"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "WARN"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardPasteWarn);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
SetTextInClipboardAndWritePermission(u"Warned_Bypassed");
FocusWebContents();
content::ExecuteScriptAsync(
rfh(), R"(var pasted_text = navigator.clipboard.readText();)");
helper.WaitForDialogToInitialize();
helper.BypassWarning();
helper.WaitForDialogToClose();
EXPECT_EQ(content::EvalJs(rfh(), "pasted_text"), "Warned_Bypassed");
}
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
PasteAllowedByDataControls) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"destinations": { "urls": ["google.com"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "BLOCK"}
]
})"});
data_controls::DesktopDataControlsDialogTestHelper helper(
data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
SetTextInClipboardAndWritePermission(u"Allowed");
FocusWebContents();
content::ExecuteScriptAsync(
rfh(), R"(var pasted_text = navigator.clipboard.readText();)");
ASSERT_FALSE(helper.dialog());
EXPECT_EQ(content::EvalJs(rfh(), "pasted_text"), "Allowed");
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
#if BUILDFLAG(IS_MAC)
#define MAYBE_ChromePrintReportsInitiator DISABLED_ChromePrintReportsInitiator
#else
#define MAYBE_ChromePrintReportsInitiator ChromePrintReportsInitiator
#endif
IN_PROC_BROWSER_TEST_F(DataProtectionClipboardBrowserTest,
MAYBE_ChromePrintReportsInitiator) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"sources": { "urls": ["http://127.0.0.1"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "BLOCK"}
]
})"});
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url()));
printing::TestPrintPreviewObserver print_preview_observer(
true);
printing::test::StartPrint(
browser()->tab_strip_model()->GetActiveWebContents());
content::WebContents* preview_web_contents =
print_preview_observer.WaitUntilPreviewIsReadyAndReturnPreviewDialog();
WriteTextToClipboard("Blocked", preview_web_contents);
base::test::TestFuture<std::u16string> future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
}
#if BUILDFLAG(IS_MAC)
#define MAYBE_ChromePrintReportsPrimaryMainFrameURLWithinSubframe \
DISABLED_ChromePrintReportsPrimaryMainFrameURLWithinSubframe
#else
#define MAYBE_ChromePrintReportsPrimaryMainFrameURLWithinSubframe \
ChromePrintReportsPrimaryMainFrameURLWithinSubframe
#endif
IN_PROC_BROWSER_TEST_F(
DataProtectionClipboardBrowserTest,
MAYBE_ChromePrintReportsPrimaryMainFrameURLWithinSubframe) {
data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
"sources": { "urls": ["a.com"] },
"restrictions": [
{"class": "CLIPBOARD", "level": "BLOCK"}
]
})"});
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)")));
content::WebContents* original_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::RenderFrameHost* main_frame =
original_contents->GetPrimaryMainFrame();
content::RenderFrameHost* sub_frame = content::ChildFrameAt(main_frame, 0);
ASSERT_EQ(sub_frame->GetLastCommittedOrigin().host(), "b.com");
printing::TestPrintPreviewObserver print_preview_observer(
true);
content::ExecuteScriptAsync(sub_frame, R"(window.print();)");
content::WebContents* preview_web_contents =
print_preview_observer.WaitUntilPreviewIsReadyAndReturnPreviewDialog();
WriteTextToClipboard("Blocked", preview_web_contents);
base::test::TestFuture<std::u16string> future;
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, nullptr,
future.GetCallback());
ASSERT_TRUE(future.Wait());
EXPECT_TRUE(future.Get().empty());
}
#endif
}