| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_handle_drop.h" |
| |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_util.h" |
| #include "base/optional.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/post_task.h" |
| #include "base/task/thread_pool.h" |
| #include "base/task_runner_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h" |
| #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_contents_view_delegate.h" |
| #include "content/public/common/drop_data.h" |
| |
| namespace { |
| |
| void DeepScanCompletionCallback( |
| content::WebContentsViewDelegate::DropCompletionCallback callback, |
| const safe_browsing::DeepScanningDialogDelegate::Data& data, |
| const safe_browsing::DeepScanningDialogDelegate::Result& result) { |
| // If any result is negative, block the drop. |
| const auto all_true_fn = [](const auto& vec) { |
| return std::all_of(vec.cbegin(), vec.cend(), [](bool b) { return b; }); |
| }; |
| bool all_true = |
| all_true_fn(result.text_results) && all_true_fn(result.paths_results); |
| |
| std::move(callback).Run( |
| all_true |
| ? content::WebContentsViewDelegate::DropCompletionResult::kContinue |
| : content::WebContentsViewDelegate::DropCompletionResult::kAbort); |
| } |
| |
| safe_browsing::DeepScanningDialogDelegate::Data GetPathsToScan( |
| content::WebContents* web_contents, |
| const content::DropData& drop_data, |
| safe_browsing::DeepScanningDialogDelegate::Data data) { |
| for (const auto& file : drop_data.filenames) { |
| base::File::Info info; |
| |
| // Ignore the path if it's a symbolic link. |
| if (!base::GetFileInfo(file.path, &info) || info.is_symbolic_link) |
| continue; |
| |
| // If the file is a directory, recursively add the files it holds to |data|. |
| if (info.is_directory) { |
| base::FileEnumerator file_enumerator(file.path, /*recursive=*/true, |
| base::FileEnumerator::FILES); |
| for (base::FilePath sub_path = file_enumerator.Next(); !sub_path.empty(); |
| sub_path = file_enumerator.Next()) { |
| data.paths.push_back(sub_path); |
| } |
| } else { |
| data.paths.push_back(file.path); |
| } |
| } |
| |
| return data; |
| } |
| |
| void ScanData(content::WebContents* web_contents, |
| content::WebContentsViewDelegate::DropCompletionCallback callback, |
| safe_browsing::DeepScanningDialogDelegate::Data data) { |
| safe_browsing::DeepScanningDialogDelegate::ShowForWebContents( |
| web_contents, std::move(data), |
| base::BindOnce(&DeepScanCompletionCallback, std::move(callback)), |
| safe_browsing::DeepScanAccessPoint::DRAG_AND_DROP); |
| } |
| |
| } // namespace |
| |
| void HandleOnPerformDrop( |
| content::WebContents* web_contents, |
| const content::DropData& drop_data, |
| content::WebContentsViewDelegate::DropCompletionCallback callback) { |
| safe_browsing::DeepScanningDialogDelegate::Data data; |
| Profile* profile = |
| Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| auto connector = |
| drop_data.filenames.empty() |
| ? enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY |
| : enterprise_connectors::AnalysisConnector::FILE_ATTACHED; |
| if (!safe_browsing::DeepScanningDialogDelegate::IsEnabled( |
| profile, web_contents->GetLastCommittedURL(), &data, connector)) { |
| std::move(callback).Run( |
| content::WebContentsViewDelegate::DropCompletionResult::kContinue); |
| return; |
| } |
| |
| // Collect the data that needs to be scanned. |
| if (!drop_data.url_title.empty()) |
| data.text.push_back(drop_data.url_title); |
| if (drop_data.text) |
| data.text.push_back(*drop_data.text); |
| if (drop_data.html) |
| data.text.push_back(*drop_data.html); |
| if (!drop_data.file_contents.empty()) |
| data.text.push_back(base::UTF8ToUTF16(drop_data.file_contents)); |
| |
| if (drop_data.filenames.empty()) { |
| ScanData(web_contents, std::move(callback), std::move(data)); |
| } else { |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, |
| base::BindOnce(&GetPathsToScan, web_contents, std::move(drop_data), |
| std::move(data)), |
| base::BindOnce(&ScanData, web_contents, std::move(callback))); |
| } |
| } |