#include "chrome/browser/enterprise/data_protection/data_protection_clipboard_utils.h"
#include <algorithm>
#include <memory>
#include <queue>
#include <variant>
#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_info.h"
#include "chrome/browser/enterprise/data_controls/chrome_clipboard_context.h"
#include "chrome/browser/enterprise/data_controls/chrome_rules_service.h"
#include "chrome/browser/enterprise/data_controls/data_controls_dialog_factory.h"
#include "chrome/browser/enterprise/data_protection/paste_allowed_request.h"
#include "chrome/browser/profiles/profile.h"
#include "components/enterprise/common/files_scan_data.h"
#include "components/enterprise/connectors/core/connectors_prefs.h"
#include "components/enterprise/connectors/core/features.h"
#include "components/enterprise/content/clipboard_restriction_service.h"
#include "components/enterprise/data_controls/content/browser/last_replaced_clipboard_data.h"
#include "components/enterprise/data_controls/core/browser/prefs.h"
#include "components/policy/core/common/policy_types.h"
#include "components/safe_browsing/buildflags.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/clipboard_types.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_metadata.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/clipboard_observer.h"
#include "ui/base/clipboard/clipboard_sequence_number_token.h"
#include "ui/base/clipboard/clipboard_util.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
#include "ui/base/l10n/l10n_util.h"
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
#endif
#if BUILDFLAG(ENTERPRISE_DATA_CONTROLS)
#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog_factory.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/enterprise/data_controls/android_data_controls_dialog.h"
#include "chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.h"
#include "components/enterprise/data_controls/core/browser/features.h"
#endif
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
#include "chrome/browser/enterprise/connectors/reporting/reporting_event_router_factory.h"
#endif
namespace enterprise_data_protection {
namespace {
GURL GetUrlFromEndpoint(const content::ClipboardEndpoint& endpoint) {
if (!endpoint.data_transfer_endpoint() ||
!endpoint.data_transfer_endpoint()->IsUrlType() ||
!endpoint.data_transfer_endpoint()->GetURL()) {
return GURL();
}
return *endpoint.data_transfer_endpoint()->GetURL();
}
bool SkipDataControlOrContentAnalysisChecks(
const content::ClipboardEndpoint& main_endpoint) {
auto* web_contents = main_endpoint.web_contents();
if (!web_contents) {
return true;
}
return false;
}
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
void HandleFileData(
content::WebContents* web_contents,
enterprise_connectors::ContentAnalysisDelegate::Data dialog_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback) {
enterprise_connectors::ContentAnalysisDelegate::CreateForFilesInWebContents(
web_contents, std::move(dialog_data),
base::BindOnce(
[](content::ContentBrowserClient::IsClipboardPasteAllowedCallback
callback,
std::vector<base::FilePath> paths, std::vector<bool> results) {
std::optional<content::ClipboardPasteData> clipboard_paste_data;
bool all_blocked =
std::all_of(results.begin(), results.end(),
[](bool allowed) { return !allowed; });
if (!all_blocked) {
std::vector<base::FilePath> allowed_paths;
allowed_paths.reserve(paths.size());
for (size_t i = 0; i < paths.size(); ++i) {
if (results[i]) {
allowed_paths.emplace_back(std::move(paths[i]));
}
}
clipboard_paste_data = content::ClipboardPasteData();
clipboard_paste_data->file_paths = std::move(allowed_paths);
}
std::move(callback).Run(std::move(clipboard_paste_data));
},
std::move(callback)),
enterprise_connectors::DeepScanAccessPoint::PASTE);
}
void HandleStringData(
content::WebContents* web_contents,
content::ClipboardPasteData clipboard_paste_data,
enterprise_connectors::ContentAnalysisDelegate::Data dialog_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback) {
enterprise_connectors::ContentAnalysisDelegate::CreateForWebContents(
web_contents, std::move(dialog_data),
base::BindOnce(
[](content::ClipboardPasteData clipboard_paste_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback
callback,
const enterprise_connectors::ContentAnalysisDelegate::Data& data,
enterprise_connectors::ContentAnalysisDelegate::Result& result) {
bool text_blocked =
!result.text_results.empty() && !result.text_results[0];
bool image_blocked = false;
if (data.settings.cloud_or_local_settings.is_local_analysis() ||
base::FeatureList::IsEnabled(
enterprise_connectors::kDlpScanPastedImages)) {
image_blocked =
!clipboard_paste_data.png.empty() && !result.image_result;
}
if (text_blocked || image_blocked) {
std::move(callback).Run(std::nullopt);
return;
}
std::move(callback).Run(std::move(clipboard_paste_data));
},
std::move(clipboard_paste_data), std::move(callback)),
enterprise_connectors::DeepScanAccessPoint::PASTE);
}
void PasteIfAllowedByContentAnalysis(
content::WebContents* web_contents,
const content::ClipboardEndpoint& source,
const content::ClipboardEndpoint& destination,
const ui::ClipboardMetadata& metadata,
content::ClipboardPasteData clipboard_paste_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback) {
DCHECK(web_contents);
DCHECK(!SkipDataControlOrContentAnalysisChecks(destination));
if (destination.web_contents()->GetPrimaryMainFrame()->IsClipboardOwner(
metadata.seqno)) {
ReplaceSameTabClipboardDataIfRequiredByPolicy(metadata.seqno,
clipboard_paste_data);
std::move(callback).Run(std::move(clipboard_paste_data));
return;
}
Profile* profile = Profile::FromBrowserContext(destination.browser_context());
if (!profile) {
std::move(callback).Run(std::move(clipboard_paste_data));
return;
}
bool is_files =
metadata.format_type == ui::ClipboardFormatType::FilenamesType();
enterprise_connectors::AnalysisConnector connector =
is_files ? enterprise_connectors::AnalysisConnector::FILE_ATTACHED
: enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY;
enterprise_connectors::ContentAnalysisDelegate::Data dialog_data;
if (!enterprise_connectors::ContentAnalysisDelegate::IsEnabled(
profile, GetUrlFromEndpoint(destination), &dialog_data, connector)) {
std::move(callback).Run(std::move(clipboard_paste_data));
return;
}
dialog_data.reason =
enterprise_connectors::ContentAnalysisRequest::CLIPBOARD_PASTE;
dialog_data.clipboard_source =
data_controls::ChromeClipboardContext::GetClipboardSource(
source, destination,
enterprise_connectors::kOnBulkDataEntryScopePref);
dialog_data.source_content_area_email =
enterprise_connectors::ContentAreaUserProvider::GetUser(source);
if (is_files) {
dialog_data.paths = std::move(clipboard_paste_data.file_paths);
HandleFileData(web_contents, std::move(dialog_data), std::move(callback));
} else {
dialog_data.AddClipboardData(clipboard_paste_data);
HandleStringData(web_contents, std::move(clipboard_paste_data),
std::move(dialog_data), std::move(callback));
}
}
#endif
data_controls::DataControlsDialogFactory* GetDialogFactory() {
#if BUILDFLAG(IS_ANDROID)
return data_controls::AndroidDataControlsDialogFactory::GetInstance();
#elif BUILDFLAG(ENTERPRISE_DATA_CONTROLS)
return data_controls::DesktopDataControlsDialogFactory::GetInstance();
#else
return nullptr;
#endif
}
void MaybeReportDataControlsPaste(const content::ClipboardEndpoint& source,
const content::ClipboardEndpoint& destination,
const ui::ClipboardMetadata& metadata,
const data_controls::Verdict& verdict,
bool bypassed = false) {
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
auto* router =
enterprise_connectors::ReportingEventRouterFactory::GetForBrowserContext(
destination.browser_context());
if (!router) {
return;
}
data_controls::ChromeClipboardContext context(source, destination, metadata);
if (bypassed) {
router->ReportPasteWarningBypassed(context, verdict);
} else {
router->ReportPaste(context, verdict);
}
#endif
}
void MaybeReportDataControlsCopy(const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const data_controls::Verdict& verdict,
bool bypassed = false) {
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
auto* router =
enterprise_connectors::ReportingEventRouterFactory::GetForBrowserContext(
source.browser_context());
if (!router) {
return;
}
data_controls::ChromeClipboardContext context(source, metadata);
if (bypassed) {
router->ReportCopyWarningBypassed(context, verdict);
} else {
router->ReportCopy(context, verdict);
}
#endif
}
void OnDataControlsPasteWarning(
const content::ClipboardEndpoint& source,
const content::ClipboardEndpoint& destination,
const ui::ClipboardMetadata& metadata,
data_controls::Verdict verdict,
content::ClipboardPasteData clipboard_paste_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback,
bool bypassed) {
if (!bypassed || SkipDataControlOrContentAnalysisChecks(destination)) {
std::move(callback).Run(std::nullopt);
return;
}
if (bypassed && verdict.level() == data_controls::Rule::Level::kWarn) {
MaybeReportDataControlsPaste(source, destination, metadata, verdict,
true);
}
if (source.browser_context() &&
metadata.seqno == data_controls::GetLastReplacedClipboardData().seqno) {
clipboard_paste_data =
data_controls::GetLastReplacedClipboardData().clipboard_paste_data;
}
#if BUILDFLAG(IS_ANDROID) || !BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
std::move(callback).Run(std::move(clipboard_paste_data));
#else
PasteIfAllowedByContentAnalysis(
destination.web_contents(), source, destination, metadata,
std::move(clipboard_paste_data), std::move(callback));
#endif
}
void PasteIfAllowedByDataControls(
const content::ClipboardEndpoint& source,
const content::ClipboardEndpoint& destination,
const ui::ClipboardMetadata& metadata,
content::ClipboardPasteData clipboard_paste_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback) {
DCHECK(!SkipDataControlOrContentAnalysisChecks(destination));
auto verdict = data_controls::ChromeRulesServiceFactory::GetInstance()
->GetForBrowserContext(destination.browser_context())
->GetPasteVerdict(source, destination);
if (source.browser_context() &&
source.browser_context() != destination.browser_context()) {
verdict = data_controls::Verdict::MergePasteVerdicts(
data_controls::ChromeRulesServiceFactory::GetInstance()
->GetForBrowserContext(source.browser_context())
->GetPasteVerdict(source, destination),
std::move(verdict));
}
auto* factory = GetDialogFactory();
if (verdict.level() == data_controls::Rule::Level::kBlock) {
MaybeReportDataControlsPaste(source, destination, metadata, verdict);
if (factory) {
factory->ShowDialogIfNeeded(
destination.web_contents(),
data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
}
std::move(callback).Run(std::nullopt);
return;
} else if (verdict.level() == data_controls::Rule::Level::kWarn) {
MaybeReportDataControlsPaste(source, destination, metadata, verdict);
if (factory) {
factory->ShowDialogIfNeeded(
destination.web_contents(),
data_controls::DataControlsDialog::Type::kClipboardPasteWarn,
base::BindOnce(&OnDataControlsPasteWarning, source, destination,
metadata, std::move(verdict),
std::move(clipboard_paste_data), std::move(callback)));
} else {
std::move(callback).Run(std::nullopt);
}
return;
} else if (verdict.level() == data_controls::Rule::Level::kReport) {
MaybeReportDataControlsPaste(source, destination, metadata, verdict);
}
if (source.browser_context() &&
metadata.seqno == data_controls::GetLastReplacedClipboardData().seqno) {
clipboard_paste_data =
data_controls::GetLastReplacedClipboardData().clipboard_paste_data;
}
#if BUILDFLAG(IS_ANDROID) || !BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
std::move(callback).Run(std::move(clipboard_paste_data));
#else
PasteIfAllowedByContentAnalysis(
destination.web_contents(), source, destination, metadata,
std::move(clipboard_paste_data), std::move(callback));
#endif
}
#if !BUILDFLAG(IS_ANDROID)
void OnDlpRulesCheckDone(
const content::ClipboardEndpoint& source,
const content::ClipboardEndpoint& destination,
const ui::ClipboardMetadata& metadata,
content::ClipboardPasteData clipboard_paste_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback,
bool allowed) {
if (!allowed || SkipDataControlOrContentAnalysisChecks(destination)) {
std::move(callback).Run(std::nullopt);
return;
}
PasteIfAllowedByDataControls(source, destination, metadata,
std::move(clipboard_paste_data),
std::move(callback));
}
#endif
void IsCopyToOSClipboardRestricted(
const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const content::ClipboardPasteData& data,
content::ContentBrowserClient::IsClipboardCopyAllowedCallback callback) {
if (SkipDataControlOrContentAnalysisChecks(source)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
auto verdict = data_controls::ChromeRulesServiceFactory::GetInstance()
->GetForBrowserContext(source.browser_context())
->GetCopyToOSClipboardVerdict(GetUrlFromEndpoint(source));
if (verdict.level() == data_controls::Rule::Level::kBlock) {
data_controls::LastReplacedClipboardDataObserver::GetInstance()
->AddDataToNextSeqno(data);
std::move(callback).Run(
metadata.format_type, data,
l10n_util::GetStringUTF16(
IDS_ENTERPRISE_DATA_CONTROLS_COPY_PREVENTION_WARNING_MESSAGE));
return;
}
std::move(callback).Run(metadata.format_type, data, std::nullopt);
}
void OnDataControlsCopyWarning(
const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const content::ClipboardPasteData& data,
data_controls::Verdict verdict,
content::ContentBrowserClient::IsClipboardCopyAllowedCallback callback,
bool bypassed) {
if (bypassed) {
MaybeReportDataControlsCopy(source, metadata, verdict, true);
IsCopyToOSClipboardRestricted(source, metadata, data, std::move(callback));
return;
}
std::move(callback).Run(metadata.format_type, content::ClipboardPasteData(),
std::nullopt);
}
void IsCopyRestrictedByDialog(
const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const content::ClipboardPasteData& data,
content::ContentBrowserClient::IsClipboardCopyAllowedCallback callback,
data_controls::DataControlsDialog::Type block_dialog_type,
data_controls::DataControlsDialog::Type warn_dialog_type) {
if (SkipDataControlOrContentAnalysisChecks(source)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
auto source_only_verdict =
data_controls::ChromeRulesServiceFactory::GetInstance()
->GetForBrowserContext(source.browser_context())
->GetCopyRestrictedBySourceVerdict(GetUrlFromEndpoint(source));
auto* factory = GetDialogFactory();
if (source_only_verdict.level() == data_controls::Rule::Level::kBlock) {
MaybeReportDataControlsCopy(source, metadata, source_only_verdict);
if (factory) {
factory->ShowDialogIfNeeded(source.web_contents(), block_dialog_type);
}
std::move(callback).Run(metadata.format_type, content::ClipboardPasteData(),
std::nullopt);
return;
}
auto os_clipboard_verdict =
data_controls::ChromeRulesServiceFactory::GetInstance()
->GetForBrowserContext(source.browser_context())
->GetCopyToOSClipboardVerdict(GetUrlFromEndpoint(source));
if (source_only_verdict.level() == data_controls::Rule::Level::kWarn ||
os_clipboard_verdict.level() == data_controls::Rule::Level::kWarn) {
auto verdict = data_controls::Verdict::MergeCopyWarningVerdicts(
std::move(source_only_verdict), std::move(os_clipboard_verdict));
MaybeReportDataControlsCopy(source, metadata, verdict);
if (factory) {
factory->ShowDialogIfNeeded(
source.web_contents(), warn_dialog_type,
base::BindOnce(&OnDataControlsCopyWarning, source, metadata, data,
std::move(verdict), std::move(callback)));
} else {
std::move(callback).Run(metadata.format_type,
content::ClipboardPasteData(),
std::nullopt);
}
return;
}
if (source_only_verdict.level() == data_controls::Rule::Level::kReport) {
MaybeReportDataControlsCopy(source, metadata, source_only_verdict);
}
IsCopyToOSClipboardRestricted(source, metadata, data, std::move(callback));
}
content::ClipboardEndpoint MakeClipboardEndpoint(
ui::DataTransferEndpoint dte,
content::RenderFrameHost* rfh) {
return content::ClipboardEndpoint(
dte,
base::BindRepeating(
[](content::GlobalRenderFrameHostId rfh_id)
-> content::BrowserContext* {
auto* rfh = content::RenderFrameHost::FromID(rfh_id);
if (!rfh) {
return nullptr;
}
return rfh->GetBrowserContext();
},
rfh->GetGlobalId()),
*rfh);
}
}
void PasteIfAllowedByPolicy(
const content::ClipboardEndpoint& source,
const content::ClipboardEndpoint& destination,
const ui::ClipboardMetadata& metadata,
content::ClipboardPasteData clipboard_paste_data,
content::ContentBrowserClient::IsClipboardPasteAllowedCallback callback) {
#if BUILDFLAG(IS_ANDROID)
if (SkipDataControlOrContentAnalysisChecks(destination)) {
std::move(callback).Run(std::nullopt);
return;
} else if (base::FeatureList::IsEnabled(
data_controls::kEnableClipboardDataControlsAndroid)) {
PasteIfAllowedByDataControls(source, destination, metadata,
std::move(clipboard_paste_data),
std::move(callback));
return;
} else {
std::move(callback).Run(std::move(clipboard_paste_data));
return;
}
#else
if (ui::DataTransferPolicyController::HasInstance()) {
std::variant<size_t, std::vector<base::FilePath>> pasted_content;
if (clipboard_paste_data.file_paths.empty()) {
DCHECK(metadata.size.has_value());
pasted_content = *metadata.size;
} else {
pasted_content = clipboard_paste_data.file_paths;
}
std::optional<ui::DataTransferEndpoint> destination_endpoint = std::nullopt;
if (destination.browser_context() &&
!destination.browser_context()->IsOffTheRecord()) {
destination_endpoint = destination.data_transfer_endpoint();
}
ui::DataTransferPolicyController::Get()->PasteIfAllowed(
source.data_transfer_endpoint(), destination_endpoint,
std::move(pasted_content),
destination.web_contents()
? destination.web_contents()->GetPrimaryMainFrame()
: nullptr,
base::BindOnce(&OnDlpRulesCheckDone, source, destination, metadata,
std::move(clipboard_paste_data), std::move(callback)));
return;
}
OnDlpRulesCheckDone(source, destination, metadata,
std::move(clipboard_paste_data), std::move(callback),
true);
#endif
}
void IsClipboardCopyAllowedByPolicy(
const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const content::ClipboardPasteData& data,
content::ContentBrowserClient::IsClipboardCopyAllowedCallback callback) {
#if BUILDFLAG(IS_ANDROID)
if (!base::FeatureList::IsEnabled(
data_controls::kEnableClipboardDataControlsAndroid)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
#endif
if (SkipDataControlOrContentAnalysisChecks(source)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
DCHECK(source.web_contents());
DCHECK(source.browser_context());
#if !BUILDFLAG(IS_ANDROID)
std::u16string replacement_data;
ClipboardRestrictionService* service =
ClipboardRestrictionServiceFactory::GetInstance()->GetForBrowserContext(
source.browser_context());
if (!service->IsUrlAllowedToCopy(GetUrlFromEndpoint(source),
metadata.size.value_or(0),
&replacement_data)) {
std::move(callback).Run(metadata.format_type, data,
std::move(replacement_data));
return;
}
#endif
IsCopyRestrictedByDialog(
source, metadata, data, std::move(callback),
data_controls::DataControlsDialog::Type::kClipboardCopyBlock,
data_controls::DataControlsDialog::Type::kClipboardCopyWarn);
}
#if BUILDFLAG(IS_ANDROID)
void IsClipboardShareAllowedByPolicy(
const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const content::ClipboardPasteData& data,
content::ContentBrowserClient::IsClipboardCopyAllowedCallback callback) {
if (!base::FeatureList::IsEnabled(
data_controls::kEnableClipboardDataControlsAndroid)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
if (SkipDataControlOrContentAnalysisChecks(source)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
DCHECK(source.web_contents());
DCHECK(source.browser_context());
IsCopyRestrictedByDialog(
source, metadata, data, std::move(callback),
data_controls::DataControlsDialog::Type::kClipboardShareBlock,
data_controls::DataControlsDialog::Type::kClipboardShareWarn);
}
void IsClipboardGenericCopyActionAllowedByPolicy(
const content::ClipboardEndpoint& source,
const ui::ClipboardMetadata& metadata,
const content::ClipboardPasteData& data,
content::ContentBrowserClient::IsClipboardCopyAllowedCallback callback) {
if (!base::FeatureList::IsEnabled(
data_controls::kEnableClipboardDataControlsAndroid)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
if (SkipDataControlOrContentAnalysisChecks(source)) {
std::move(callback).Run(metadata.format_type, data, std::nullopt);
return;
}
DCHECK(source.web_contents());
DCHECK(source.browser_context());
IsCopyRestrictedByDialog(
source, metadata, data, std::move(callback),
data_controls::DataControlsDialog::Type::kClipboardActionBlock,
data_controls::DataControlsDialog::Type::kClipboardActionWarn);
}
#endif
void ReplaceSameTabClipboardDataIfRequiredByPolicy(
ui::ClipboardSequenceNumberToken seqno,
content::ClipboardPasteData& data) {
if (seqno == data_controls::GetLastReplacedClipboardData().seqno) {
data = data_controls::GetLastReplacedClipboardData().clipboard_paste_data;
}
}
bool HandleWriteTextToClipboard(content::WebContents* web_contents,
ui::ClipboardBuffer clipboard_buffer,
const std::u16string_view& text) {
if (clipboard_buffer == ui::ClipboardBuffer::kSelection) {
return false;
}
content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame();
if (!rfh) {
return false;
}
ui::DataTransferEndpoint dte(
rfh->GetMainFrame()->GetLastCommittedURL(),
{.off_the_record = rfh->GetBrowserContext()->IsOffTheRecord()});
content::ClipboardEndpoint clipboard_endpoint =
MakeClipboardEndpoint(dte, rfh);
content::ClipboardPasteData data;
data.text = text;
auto meta = ui::ClipboardMetadata{
.size = data.text.size() * sizeof(std::u16string::value_type),
.format_type = ui::ClipboardFormatType::PlainTextType(),
};
IsClipboardCopyAllowedByPolicy(
std::move(clipboard_endpoint), meta, std::move(data),
base::BindOnce(
[](ui::ClipboardBuffer clipboard_buffer,
std::unique_ptr<ui::DataTransferEndpoint> dte,
const ui::ClipboardFormatType& data_type,
const content::ClipboardPasteData& data,
std::optional<std::u16string> replacement_data) {
ui::ScopedClipboardWriter scw(clipboard_buffer, std::move(dte));
if (replacement_data) {
scw.WriteText(std::move(*replacement_data));
} else {
scw.WriteText(data.text);
}
},
clipboard_buffer,
std::make_unique<ui::DataTransferEndpoint>(std::move(dte))));
return true;
}
bool DragAndDropForTextIsAllowed(content::WebContents* web_contents) {
content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame();
if (!rfh) {
return true;
}
auto url = rfh->GetMainFrame()->GetLastCommittedURL();
if (!url.is_valid()) {
return true;
}
ui::DataTransferEndpoint dte(
url, {.off_the_record = rfh->GetBrowserContext()->IsOffTheRecord()});
content::ClipboardEndpoint source = MakeClipboardEndpoint(dte, rfh);
if (SkipDataControlOrContentAnalysisChecks(source)) {
return true;
}
auto verdict = data_controls::ChromeRulesServiceFactory::GetInstance()
->GetForBrowserContext(source.browser_context())
->GetCopyToOSClipboardVerdict(GetUrlFromEndpoint(source));
return verdict.level() != data_controls::Rule::Level::kBlock;
}
bool CanPopulateFindBarFromSelection(content::WebContents* web_contents) {
return DragAndDropForTextIsAllowed(web_contents);
}
}