blob: 341bf7ebd0eeb4efab270aa81c9d26db589debe0 [file] [log] [blame]
// Copyright 2019 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/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "base/command_line.h"
#include "base/rand_util.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/connectors/analysis/analysis_settings.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/cloud_binary_upload_service_factory.h"
#include "components/enterprise/common/strings.h"
#include "net/base/url_util.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#include "chrome/browser/enterprise/connectors/analysis/local_binary_upload_service_factory.h"
#endif
namespace safe_browsing {
namespace {
constexpr char kCloudBinaryUploadServiceUrlFlag[] = "binary-upload-service-url";
absl::optional<GURL> GetUrlOverride() {
// Ignore this flag on Stable and Beta to avoid abuse.
if (!g_browser_process || !g_browser_process->browser_policy_connector()
->IsCommandLineSwitchSupported()) {
return absl::nullopt;
}
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kCloudBinaryUploadServiceUrlFlag)) {
GURL url = GURL(
command_line->GetSwitchValueASCII(kCloudBinaryUploadServiceUrlFlag));
if (url.is_valid())
return url;
else
LOG(ERROR) << "--binary-upload-service-url is set to an invalid URL";
}
return absl::nullopt;
}
} // namespace
std::string BinaryUploadService::ResultToString(Result result) {
switch (result) {
case Result::UNKNOWN:
return "UNKNOWN";
case Result::SUCCESS:
return "SUCCESS";
case Result::UPLOAD_FAILURE:
return "UPLOAD_FAILURE";
case Result::TIMEOUT:
return "TIMEOUT";
case Result::FILE_TOO_LARGE:
return "FILE_TOO_LARGE";
case Result::FAILED_TO_GET_TOKEN:
return "FAILED_TO_GET_TOKEN";
case Result::UNAUTHORIZED:
return "UNAUTHORIZED";
case Result::FILE_ENCRYPTED:
return "FILE_ENCRYPTED";
case Result::DLP_SCAN_UNSUPPORTED_FILE_TYPE:
return "DLP_SCAN_UNSUPPORTED_FILE_TYPE";
case Result::TOO_MANY_REQUESTS:
return "TOO_MANY_REQUESTS";
}
}
BinaryUploadService::Request::Data::Data() = default;
BinaryUploadService::Request::Data::Data(const Data& other) {
operator=(other);
}
BinaryUploadService::Request::Data::Data(Data&&) = default;
BinaryUploadService::Request::Data&
BinaryUploadService::Request::Data::operator=(
const BinaryUploadService::Request::Data& other) {
contents = other.contents;
path = other.path;
hash = other.hash;
size = other.size;
page = other.page.Duplicate();
return *this;
}
BinaryUploadService::Request::Data&
BinaryUploadService::Request::Data::operator=(
BinaryUploadService::Request::Data&& other) = default;
BinaryUploadService::Request::Data::~Data() = default;
BinaryUploadService::Request::Request(
ContentAnalysisCallback callback,
enterprise_connectors::CloudOrLocalAnalysisSettings settings)
: content_analysis_callback_(std::move(callback)),
cloud_or_local_settings_(std::move(settings)) {}
BinaryUploadService::Request::Request(
ContentAnalysisCallback content_analysis_callback,
enterprise_connectors::CloudOrLocalAnalysisSettings settings,
Request::RequestStartCallback start_callback)
: content_analysis_callback_(std::move(content_analysis_callback)),
request_start_callback_(std::move(start_callback)),
cloud_or_local_settings_(std::move(settings)) {}
BinaryUploadService::Request::~Request() = default;
void BinaryUploadService::Request::set_per_profile_request(
bool per_profile_request) {
per_profile_request_ = per_profile_request;
}
bool BinaryUploadService::Request::per_profile_request() const {
return per_profile_request_;
}
void BinaryUploadService::Request::set_fcm_token(const std::string& token) {
content_analysis_request_.set_fcm_notification_token(token);
}
void BinaryUploadService::Request::set_device_token(const std::string& token) {
content_analysis_request_.set_device_token(token);
}
void BinaryUploadService::Request::set_filename(const std::string& filename) {
content_analysis_request_.mutable_request_data()->set_filename(filename);
}
void BinaryUploadService::Request::set_digest(const std::string& digest) {
content_analysis_request_.mutable_request_data()->set_digest(digest);
}
void BinaryUploadService::Request::clear_dlp_scan_request() {
auto* tags = content_analysis_request_.mutable_tags();
auto it = base::ranges::find(*tags, "dlp");
if (it != tags->end())
tags->erase(it);
}
void BinaryUploadService::Request::set_analysis_connector(
enterprise_connectors::AnalysisConnector connector) {
content_analysis_request_.set_analysis_connector(connector);
}
void BinaryUploadService::Request::set_url(const std::string& url) {
content_analysis_request_.mutable_request_data()->set_url(url);
}
void BinaryUploadService::Request::set_source(const std::string& source) {
content_analysis_request_.mutable_request_data()->set_source(source);
}
void BinaryUploadService::Request::set_destination(
const std::string& destination) {
content_analysis_request_.mutable_request_data()->set_destination(
destination);
}
void BinaryUploadService::Request::set_csd(ClientDownloadRequest csd) {
*content_analysis_request_.mutable_request_data()->mutable_csd() =
std::move(csd);
}
void BinaryUploadService::Request::add_tag(const std::string& tag) {
content_analysis_request_.add_tags(tag);
}
void BinaryUploadService::Request::set_email(const std::string& email) {
content_analysis_request_.mutable_request_data()->set_email(email);
}
void BinaryUploadService::Request::set_client_metadata(
enterprise_connectors::ClientMetadata metadata) {
*content_analysis_request_.mutable_client_metadata() = std::move(metadata);
}
void BinaryUploadService::Request::set_content_type(const std::string& type) {
content_analysis_request_.mutable_request_data()->set_content_type(type);
}
void BinaryUploadService::Request::set_tab_title(const std::string& tab_title) {
content_analysis_request_.mutable_request_data()->set_tab_title(tab_title);
}
void BinaryUploadService::Request::set_user_action_id(
const std::string& user_action_id) {
content_analysis_request_.set_user_action_id(user_action_id);
}
void BinaryUploadService::Request::set_user_action_requests_count(
uint64_t user_action_requests_count) {
content_analysis_request_.set_user_action_requests_count(
user_action_requests_count);
}
void BinaryUploadService::Request::set_tab_url(const GURL& tab_url) {
content_analysis_request_.mutable_request_data()->set_tab_url(tab_url.spec());
}
void BinaryUploadService::Request::set_printer_name(
const std::string& printer_name) {
content_analysis_request_.mutable_request_data()
->mutable_print_metadata()
->set_printer_name(printer_name);
}
void BinaryUploadService::Request::set_printer_type(
enterprise_connectors::ContentMetaData::PrintMetadata::PrinterType
printer_type) {
content_analysis_request_.mutable_request_data()
->mutable_print_metadata()
->set_printer_type(printer_type);
}
std::string BinaryUploadService::Request::SetRandomRequestToken() {
DCHECK(request_token().empty());
std::string token = base::RandBytesAsString(128);
content_analysis_request_.set_request_token(
base::HexEncode(token.data(), token.size()));
return content_analysis_request_.request_token();
}
enterprise_connectors::AnalysisConnector
BinaryUploadService::Request::analysis_connector() {
return content_analysis_request_.analysis_connector();
}
const std::string& BinaryUploadService::Request::device_token() const {
return content_analysis_request_.device_token();
}
const std::string& BinaryUploadService::Request::request_token() const {
return content_analysis_request_.request_token();
}
const std::string& BinaryUploadService::Request::fcm_notification_token()
const {
return content_analysis_request_.fcm_notification_token();
}
const std::string& BinaryUploadService::Request::filename() const {
return content_analysis_request_.request_data().filename();
}
const std::string& BinaryUploadService::Request::digest() const {
return content_analysis_request_.request_data().digest();
}
const std::string& BinaryUploadService::Request::content_type() const {
return content_analysis_request_.request_data().content_type();
}
const std::string& BinaryUploadService::Request::user_action_id() const {
return content_analysis_request_.user_action_id();
}
const std::string& BinaryUploadService::Request::tab_title() const {
return content_analysis_request_.request_data().tab_title();
}
uint64_t BinaryUploadService::Request::user_action_requests_count() const {
return content_analysis_request_.user_action_requests_count();
}
GURL BinaryUploadService::Request::tab_url() const {
if (!content_analysis_request_.has_request_data())
return GURL();
return GURL(content_analysis_request_.request_data().tab_url());
}
void BinaryUploadService::Request::StartRequest() {
if (!request_start_callback_.is_null())
std::move(request_start_callback_).Run(*this);
}
void BinaryUploadService::Request::FinishRequest(
Result result,
enterprise_connectors::ContentAnalysisResponse response) {
std::move(content_analysis_callback_).Run(result, response);
}
void BinaryUploadService::Request::SerializeToString(
std::string* destination) const {
content_analysis_request_.SerializeToString(destination);
}
GURL BinaryUploadService::Request::GetUrlWithParams() const {
DCHECK(absl::holds_alternative<enterprise_connectors::CloudAnalysisSettings>(
cloud_or_local_settings_));
GURL url = GetUrlOverride().value_or(cloud_or_local_settings_.analysis_url());
url = net::AppendQueryParameter(url, enterprise::kUrlParamDeviceToken,
device_token());
std::string connector;
switch (content_analysis_request_.analysis_connector()) {
case enterprise_connectors::FILE_ATTACHED:
connector = "OnFileAttached";
break;
case enterprise_connectors::FILE_DOWNLOADED:
connector = "OnFileDownloaded";
break;
case enterprise_connectors::BULK_DATA_ENTRY:
connector = "OnBulkDataEntry";
break;
case enterprise_connectors::PRINT:
connector = "OnPrint";
break;
case enterprise_connectors::FILE_TRANSFER:
connector = "OnFileTransfer";
break;
case enterprise_connectors::ANALYSIS_CONNECTOR_UNSPECIFIED:
break;
}
if (!connector.empty()) {
url = net::AppendQueryParameter(url, enterprise::kUrlParamConnector,
connector);
}
for (const std::string& tag : content_analysis_request_.tags())
url = net::AppendQueryParameter(url, enterprise::kUrlParamTag, tag);
return url;
}
bool BinaryUploadService::Request::IsAuthRequest() const {
return false;
}
const std::string& BinaryUploadService::Request::access_token() const {
return access_token_;
}
void BinaryUploadService::Request::set_access_token(
const std::string& access_token) {
access_token_ = access_token;
}
BinaryUploadService::Ack::Ack(
enterprise_connectors::CloudOrLocalAnalysisSettings settings)
: cloud_or_local_settings_(std::move(settings)) {}
BinaryUploadService::Ack::~Ack() = default;
void BinaryUploadService::Ack::set_request_token(const std::string& token) {
ack_.set_request_token(token);
}
void BinaryUploadService::Ack::set_status(
enterprise_connectors::ContentAnalysisAcknowledgement::Status status) {
ack_.set_status(status);
}
void BinaryUploadService::Ack::set_final_action(
enterprise_connectors::ContentAnalysisAcknowledgement::FinalAction
final_action) {
ack_.set_final_action(final_action);
}
BinaryUploadService::CancelRequests::CancelRequests(
enterprise_connectors::CloudOrLocalAnalysisSettings settings)
: cloud_or_local_settings_(std::move(settings)) {}
BinaryUploadService::CancelRequests::~CancelRequests() = default;
void BinaryUploadService::CancelRequests::set_user_action_id(
const std::string& user_action_id) {
user_action_id_ = user_action_id;
}
// static
BinaryUploadService* BinaryUploadService::GetForProfile(
Profile* profile,
const enterprise_connectors::AnalysisSettings& settings) {
// Local content analysis is supported only on desktop platforms.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
if (settings.cloud_or_local_settings.is_cloud_analysis()) {
return CloudBinaryUploadServiceFactory::GetForProfile(profile);
} else {
return enterprise_connectors::LocalBinaryUploadServiceFactory::
GetForProfile(profile);
}
#else
DCHECK(settings.cloud_or_local_settings.is_cloud_analysis());
return CloudBinaryUploadServiceFactory::GetForProfile(profile);
#endif
}
} // namespace safe_browsing