blob: dbc329b17512348935901f0645886960ca1a3454 [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 "weblayer/browser/safe_browsing/safe_browsing_service.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/path_service.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/android/remote_database_manager.h"
#include "components/safe_browsing/android/safe_browsing_api_handler_bridge.h"
#include "components/safe_browsing/content/browser/browser_url_loader_throttle.h"
#include "components/safe_browsing/content/browser/mojo_safe_browsing_impl.h"
#include "components/safe_browsing/content/browser/safe_browsing_navigation_throttle.h"
#include "components/safe_browsing/content/browser/safe_browsing_network_context.h"
#include "components/safe_browsing/content/browser/triggers/trigger_manager.h"
#include "components/safe_browsing/core/browser/realtime/url_lookup_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_context.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "weblayer/browser/browser_context_impl.h"
#include "weblayer/browser/browser_process.h"
#include "weblayer/browser/safe_browsing/url_checker_delegate_impl.h"
#include "weblayer/browser/safe_browsing/weblayer_safe_browsing_blocking_page_factory.h"
#include "weblayer/browser/safe_browsing/weblayer_ui_manager_delegate.h"
#include "weblayer/common/features.h"
namespace weblayer {
namespace {
network::mojom::NetworkContextParamsPtr CreateDefaultNetworkContextParams(
const std::string& user_agent) {
network::mojom::NetworkContextParamsPtr network_context_params =
network::mojom::NetworkContextParams::New();
network_context_params->cert_verifier_params = content::GetCertVerifierParams(
cert_verifier::mojom::CertVerifierCreationParams::New());
network_context_params->user_agent = user_agent;
return network_context_params;
}
// Helper method that checks the RenderProcessHost is still alive and checks the
// latest Safe Browsing pref value on the UI thread before hopping over to the
// IO thread.
void MaybeCreateSafeBrowsing(
int rph_id,
base::WeakPtr<content::ResourceContext> resource_context,
base::RepeatingCallback<scoped_refptr<safe_browsing::UrlCheckerDelegate>()>
get_checker_delegate,
mojo::PendingReceiver<safe_browsing::mojom::SafeBrowsing> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::RenderProcessHost* render_process_host =
content::RenderProcessHost::FromID(rph_id);
if (!render_process_host) {
return;
}
bool is_safe_browsing_enabled = safe_browsing::IsSafeBrowsingEnabled(
*static_cast<BrowserContextImpl*>(
render_process_host->GetBrowserContext())
->pref_service());
if (!is_safe_browsing_enabled) {
return;
}
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&safe_browsing::MojoSafeBrowsingImpl::MaybeCreate, rph_id,
std::move(resource_context),
std::move(get_checker_delegate), std::move(receiver)));
}
} // namespace
SafeBrowsingService::SafeBrowsingService(const std::string& user_agent)
: user_agent_(user_agent) {}
SafeBrowsingService::~SafeBrowsingService() = default;
void SafeBrowsingService::Initialize() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (network_context_) {
// already initialized
return;
}
base::FilePath user_data_dir;
bool result =
base::PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir);
DCHECK(result);
// safebrowsing network context needs to be created on the UI thread.
network_context_ =
std::make_unique<safe_browsing::SafeBrowsingNetworkContext>(
user_data_dir, /*trigger_migration=*/false,
base::BindRepeating(CreateDefaultNetworkContextParams, user_agent_));
CreateSafeBrowsingUIManager();
// Needs to happen after |ui_manager_| is created.
CreateTriggerManager();
}
std::unique_ptr<blink::URLLoaderThrottle>
SafeBrowsingService::CreateURLLoaderThrottle(
const base::RepeatingCallback<content::WebContents*()>& wc_getter,
int frame_tree_node_id,
safe_browsing::RealTimeUrlLookupServiceBase* url_lookup_service) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return safe_browsing::BrowserURLLoaderThrottle::Create(
base::BindOnce(
[](SafeBrowsingService* sb_service) {
return sb_service->GetSafeBrowsingUrlCheckerDelegate();
},
base::Unretained(this)),
wc_getter, frame_tree_node_id,
url_lookup_service ? url_lookup_service->GetWeakPtr() : nullptr,
/*hash_realtime_service=*/nullptr);
}
std::unique_ptr<content::NavigationThrottle>
SafeBrowsingService::MaybeCreateSafeBrowsingNavigationThrottleFor(
content::NavigationHandle* handle) {
if (!base::FeatureList::IsEnabled(features::kWebLayerSafeBrowsing)) {
return nullptr;
}
return safe_browsing::SafeBrowsingNavigationThrottle::MaybeCreateThrottleFor(
handle, GetSafeBrowsingUIManager().get());
}
scoped_refptr<safe_browsing::UrlCheckerDelegate>
SafeBrowsingService::GetSafeBrowsingUrlCheckerDelegate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!safe_browsing_url_checker_delegate_) {
safe_browsing_url_checker_delegate_ = new UrlCheckerDelegateImpl(
GetSafeBrowsingDBManager(), GetSafeBrowsingUIManager());
}
return safe_browsing_url_checker_delegate_;
}
scoped_refptr<safe_browsing::RemoteSafeBrowsingDatabaseManager>
SafeBrowsingService::GetSafeBrowsingDBManager() {
if (!safe_browsing_db_manager_) {
CreateAndStartSafeBrowsingDBManager();
}
return safe_browsing_db_manager_;
}
scoped_refptr<safe_browsing::SafeBrowsingUIManager>
SafeBrowsingService::GetSafeBrowsingUIManager() {
return ui_manager_;
}
safe_browsing::TriggerManager* SafeBrowsingService::GetTriggerManager() {
return trigger_manager_.get();
}
void SafeBrowsingService::CreateSafeBrowsingUIManager() {
DCHECK(!ui_manager_);
ui_manager_ = new safe_browsing::SafeBrowsingUIManager(
std::make_unique<WebLayerSafeBrowsingUIManagerDelegate>(),
std::make_unique<WebLayerSafeBrowsingBlockingPageFactory>(),
GURL(url::kAboutBlankURL));
}
void SafeBrowsingService::CreateTriggerManager() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
trigger_manager_ = std::make_unique<safe_browsing::TriggerManager>(
ui_manager_.get(), BrowserProcess::GetInstance()->GetLocalState());
}
void SafeBrowsingService::CreateAndStartSafeBrowsingDBManager() {
DCHECK(!safe_browsing_db_manager_);
safe_browsing_db_manager_ =
new safe_browsing::RemoteSafeBrowsingDatabaseManager();
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
// Posting a task to start the DB here ensures that it will be started by
// the time that a consumer uses it on the IO thread, as such a consumer
// would need to make it available for usage on the IO thread via a
// PostTask() that will be ordered after this one.
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
&SafeBrowsingService::StartSafeBrowsingDBManagerOnIOThread,
base::Unretained(this)));
} else {
StartSafeBrowsingDBManagerOnIOThread();
}
}
void SafeBrowsingService::StartSafeBrowsingDBManagerOnIOThread() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(safe_browsing_db_manager_);
if (started_db_manager_) {
return;
}
started_db_manager_ = true;
// V4ProtocolConfig is not used. Just create one with empty values.
safe_browsing::V4ProtocolConfig config("", false, "", "");
safe_browsing_db_manager_->StartOnIOThread(GetURLLoaderFactoryOnIOThread(),
config);
}
scoped_refptr<network::SharedURLLoaderFactory>
SafeBrowsingService::GetURLLoaderFactoryOnIOThread() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!shared_url_loader_factory_on_io_) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&SafeBrowsingService::CreateURLLoaderFactoryForIO,
base::Unretained(this),
url_loader_factory_on_io_.BindNewPipeAndPassReceiver()));
shared_url_loader_factory_on_io_ =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
url_loader_factory_on_io_.get());
}
return shared_url_loader_factory_on_io_;
}
void SafeBrowsingService::CreateURLLoaderFactoryForIO(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto url_loader_factory_params =
network::mojom::URLLoaderFactoryParams::New();
url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
url_loader_factory_params->is_corb_enabled = false;
network_context_->GetNetworkContext()->CreateURLLoaderFactory(
std::move(receiver), std::move(url_loader_factory_params));
}
void SafeBrowsingService::AddInterface(
service_manager::BinderRegistry* registry,
content::RenderProcessHost* render_process_host) {
content::ResourceContext* resource_context =
render_process_host->GetBrowserContext()->GetResourceContext();
registry->AddInterface(
base::BindRepeating(
&MaybeCreateSafeBrowsing, render_process_host->GetID(),
resource_context->GetWeakPtr(),
base::BindRepeating(
&SafeBrowsingService::GetSafeBrowsingUrlCheckerDelegate,
base::Unretained(this))),
content::GetUIThreadTaskRunner({}));
}
void SafeBrowsingService::StopDBManager() {
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&SafeBrowsingService::StopDBManagerOnIOThread,
base::Unretained(this)));
}
void SafeBrowsingService::StopDBManagerOnIOThread() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (safe_browsing_db_manager_) {
safe_browsing_db_manager_->StopOnIOThread(true /*shutdown*/);
safe_browsing_db_manager_.reset();
started_db_manager_ = false;
}
}
network::mojom::NetworkContext* SafeBrowsingService::GetNetworkContext() {
if (!network_context_) {
return nullptr;
}
return network_context_->GetNetworkContext();
}
scoped_refptr<network::SharedURLLoaderFactory>
SafeBrowsingService::GetURLLoaderFactory() {
if (!network_context_) {
return nullptr;
}
return network_context_->GetURLLoaderFactory();
}
} // namespace weblayer