Commit 8851a2cf authored by Ali Juma's avatar Ali Juma Committed by Commit Bot

[iOS] Implement SafeBrowsingService

This creates an iOS version of SafeBrowsingService, which handles creating
and initializing a SafeBrowsingDatabaseManager, and also handles starting
and stopping the database manager depending on the value of the
Safe Browsing opt-out preference.

Behind the kSafeBrowsingAvailableOnIOS flag, this creates a
SafeBrowsingServiceIOS owned by ApplicationContextImpl and initialized during
IOSChromeMainParts::PreMainMessageLoopRun.

Change-Id: I5eaf3ee1a92ab55ef84eb38936a4818a246f6df9
Bug: 1028755,1049327
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2044521
Commit-Queue: Ali Juma <ajuma@chromium.org>
Reviewed-by: default avatarVarun Khaneja <vakh@chromium.org>
Reviewed-by: default avatarMaksim Orlovich <morlovich@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Reviewed-by: default avatarKurt Horimoto <kkhorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748268}
parent 9c19d6b4
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "components/safe_browsing/core/db/v4_store.h" #include "components/safe_browsing/core/db/v4_store.h"
#include "components/safe_browsing/core/proto/webui.pb.h" #include "components/safe_browsing/core/proto/webui.pb.h"
class SafeBrowsingServiceTest;
class TestSafeBrowsingDatabaseHelper; class TestSafeBrowsingDatabaseHelper;
namespace safe_browsing { namespace safe_browsing {
...@@ -177,6 +178,7 @@ class V4Database { ...@@ -177,6 +178,7 @@ class V4Database {
const std::unique_ptr<StoreMap> store_map_; const std::unique_ptr<StoreMap> store_map_;
private: private:
friend class ::SafeBrowsingServiceTest;
friend class ::TestSafeBrowsingDatabaseHelper; friend class ::TestSafeBrowsingDatabaseHelper;
friend class V4DatabaseFactory; friend class V4DatabaseFactory;
friend class V4EmbeddedTestServerBrowserTest; friend class V4EmbeddedTestServerBrowserTest;
......
...@@ -87,6 +87,9 @@ const base::Feature kRealTimeUrlLookupEnabledWithToken{ ...@@ -87,6 +87,9 @@ const base::Feature kRealTimeUrlLookupEnabledWithToken{
"SafeBrowsingRealTimeUrlLookupEnabledWithToken", "SafeBrowsingRealTimeUrlLookupEnabledWithToken",
base::FEATURE_DISABLED_BY_DEFAULT}; base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kSafeBrowsingAvailableOnIOS{
"SafeBrowsingAvailableOnIOS", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kSafeBrowsingSeparateNetworkContexts{ const base::Feature kSafeBrowsingSeparateNetworkContexts{
"SafeBrowsingSeparateNetworkContexts", base::FEATURE_DISABLED_BY_DEFAULT}; "SafeBrowsingSeparateNetworkContexts", base::FEATURE_DISABLED_BY_DEFAULT};
...@@ -138,6 +141,7 @@ constexpr struct { ...@@ -138,6 +141,7 @@ constexpr struct {
{&kPromptAppForDeepScanning, true}, {&kPromptAppForDeepScanning, true},
{&kRealTimeUrlLookupEnabled, true}, {&kRealTimeUrlLookupEnabled, true},
{&kRealTimeUrlLookupEnabledWithToken, true}, {&kRealTimeUrlLookupEnabledWithToken, true},
{&kSafeBrowsingAvailableOnIOS, true},
{&kSafeBrowsingSeparateNetworkContexts, true}, {&kSafeBrowsingSeparateNetworkContexts, true},
{&kSendOnFocusPing, true}, {&kSendOnFocusPing, true},
{&kSendPasswordReusePing, true}, {&kSendPasswordReusePing, true},
......
...@@ -69,6 +69,11 @@ extern const base::Feature kPasswordProtectionForSignedInUsers; ...@@ -69,6 +69,11 @@ extern const base::Feature kPasswordProtectionForSignedInUsers;
// Controls whether Chrome prompts Advanced Protection users for deep scanning. // Controls whether Chrome prompts Advanced Protection users for deep scanning.
extern const base::Feature kPromptAppForDeepScanning; extern const base::Feature kPromptAppForDeepScanning;
// Controls whether native (instead of WKWebView-provided) Safe Browsing
// is available on iOS. When this flag is enabled, Safe Browsing is still
// subject to an opt-out controlled by prefs::kSafeBrowsingEnabled.
extern const base::Feature kSafeBrowsingAvailableOnIOS;
// Controls whether Safe Browsing uses separate NetworkContexts for each // Controls whether Safe Browsing uses separate NetworkContexts for each
// profile. // profile.
extern const base::Feature kSafeBrowsingSeparateNetworkContexts; extern const base::Feature kSafeBrowsingSeparateNetworkContexts;
......
...@@ -205,6 +205,7 @@ source_set("browser_impl") { ...@@ -205,6 +205,7 @@ source_set("browser_impl") {
"//components/open_from_clipboard", "//components/open_from_clipboard",
"//components/prefs", "//components/prefs",
"//components/rappor", "//components/rappor",
"//components/safe_browsing/core:features",
"//components/sessions", "//components/sessions",
"//components/translate/core/browser", "//components/translate/core/browser",
"//components/ukm", "//components/ukm",
...@@ -231,6 +232,7 @@ source_set("browser_impl") { ...@@ -231,6 +232,7 @@ source_set("browser_impl") {
"//ios/chrome/browser/policy", "//ios/chrome/browser/policy",
"//ios/chrome/browser/prefs", "//ios/chrome/browser/prefs",
"//ios/chrome/browser/prefs:browser_prefs", "//ios/chrome/browser/prefs:browser_prefs",
"//ios/chrome/browser/safe_browsing",
"//ios/chrome/browser/send_tab_to_self", "//ios/chrome/browser/send_tab_to_self",
"//ios/chrome/browser/translate", "//ios/chrome/browser/translate",
"//ios/chrome/browser/update_client", "//ios/chrome/browser/update_client",
......
...@@ -66,6 +66,7 @@ include_rules = [ ...@@ -66,6 +66,7 @@ include_rules = [
"+components/rappor", "+components/rappor",
"+components/reading_list", "+components/reading_list",
"+components/rlz", "+components/rlz",
"+components/safe_browsing",
"+components/search", "+components/search",
"+components/search_engines", "+components/search_engines",
"+components/search_provider_logos", "+components/search_provider_logos",
...@@ -117,6 +118,7 @@ include_rules = [ ...@@ -117,6 +118,7 @@ include_rules = [
"+services/metrics/public", "+services/metrics/public",
"+services/metrics/public/cpp", "+services/metrics/public/cpp",
"+services/network/network_change_manager.h", "+services/network/network_change_manager.h",
"+services/network/network_context.h",
"+services/network/public/mojom", "+services/network/public/mojom",
"+services/network/public/cpp", "+services/network/public/cpp",
"+third_party/breakpad/breakpad/src/client/ios", "+third_party/breakpad/breakpad/src/client/ios",
......
...@@ -67,6 +67,7 @@ class ApplicationContext; ...@@ -67,6 +67,7 @@ class ApplicationContext;
class BrowserPolicyConnectorIOS; class BrowserPolicyConnectorIOS;
class IOSChromeIOThread; class IOSChromeIOThread;
class PrefService; class PrefService;
class SafeBrowsingService;
// Gets the global application context. Cannot return null. // Gets the global application context. Cannot return null.
ApplicationContext* GetApplicationContext(); ApplicationContext* GetApplicationContext();
...@@ -144,6 +145,9 @@ class ApplicationContext { ...@@ -144,6 +145,9 @@ class ApplicationContext {
virtual component_updater::ComponentUpdateService* virtual component_updater::ComponentUpdateService*
GetComponentUpdateService() = 0; GetComponentUpdateService() = 0;
// Gets the SafeBrowsingService.
virtual SafeBrowsingService* GetSafeBrowsingService() = 0;
// Returns the NetworkConnectionTracker instance for this ApplicationContext. // Returns the NetworkConnectionTracker instance for this ApplicationContext.
virtual network::NetworkConnectionTracker* GetNetworkConnectionTracker() = 0; virtual network::NetworkConnectionTracker* GetNetworkConnectionTracker() = 0;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "components/network_time/network_time_tracker.h" #include "components/network_time/network_time_tracker.h"
#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/features.h"
#include "components/sessions/core/session_id_generator.h" #include "components/sessions/core/session_id_generator.h"
#include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_download_manager.h"
#include "components/ukm/ukm_service.h" #include "components/ukm/ukm_service.h"
...@@ -57,6 +58,7 @@ ...@@ -57,6 +58,7 @@
#include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/pref_names.h"
#include "ios/chrome/browser/prefs/browser_prefs.h" #include "ios/chrome/browser/prefs/browser_prefs.h"
#include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h" #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
#include "ios/chrome/browser/safe_browsing/safe_browsing_service.h"
#include "ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h" #include "ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h"
#include "ios/chrome/common/channel_info.h" #include "ios/chrome/common/channel_info.h"
#include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_task_traits.h"
...@@ -160,6 +162,9 @@ void ApplicationContextImpl::StartTearDown() { ...@@ -160,6 +162,9 @@ void ApplicationContextImpl::StartTearDown() {
net_export_file_writer_.reset(); net_export_file_writer_.reset();
if (safe_browsing_service_)
safe_browsing_service_->ShutDown();
// Need to clear browser states before the IO thread. // Need to clear browser states before the IO thread.
chrome_browser_state_manager_.reset(); chrome_browser_state_manager_.reset();
...@@ -382,6 +387,16 @@ ApplicationContextImpl::GetComponentUpdateService() { ...@@ -382,6 +387,16 @@ ApplicationContextImpl::GetComponentUpdateService() {
return component_updater_.get(); return component_updater_.get();
} }
SafeBrowsingService* ApplicationContextImpl::GetSafeBrowsingService() {
DCHECK(thread_checker_.CalledOnValidThread());
if (base::FeatureList::IsEnabled(
safe_browsing::kSafeBrowsingAvailableOnIOS) &&
!safe_browsing_service_) {
safe_browsing_service_ = base::MakeRefCounted<SafeBrowsingService>();
}
return safe_browsing_service_.get();
}
network::NetworkConnectionTracker* network::NetworkConnectionTracker*
ApplicationContextImpl::GetNetworkConnectionTracker() { ApplicationContextImpl::GetNetworkConnectionTracker() {
if (!network_connection_tracker_) { if (!network_connection_tracker_) {
......
...@@ -70,6 +70,7 @@ class ApplicationContextImpl : public ApplicationContext { ...@@ -70,6 +70,7 @@ class ApplicationContextImpl : public ApplicationContext {
gcm::GCMDriver* GetGCMDriver() override; gcm::GCMDriver* GetGCMDriver() override;
component_updater::ComponentUpdateService* GetComponentUpdateService() component_updater::ComponentUpdateService* GetComponentUpdateService()
override; override;
SafeBrowsingService* GetSafeBrowsingService() override;
network::NetworkConnectionTracker* GetNetworkConnectionTracker() override; network::NetworkConnectionTracker* GetNetworkConnectionTracker() override;
BrowserPolicyConnectorIOS* GetBrowserPolicyConnector() override; BrowserPolicyConnectorIOS* GetBrowserPolicyConnector() override;
...@@ -113,6 +114,8 @@ class ApplicationContextImpl : public ApplicationContext { ...@@ -113,6 +114,8 @@ class ApplicationContextImpl : public ApplicationContext {
std::unique_ptr<network::NetworkConnectionTracker> std::unique_ptr<network::NetworkConnectionTracker>
network_connection_tracker_; network_connection_tracker_;
scoped_refptr<SafeBrowsingService> safe_browsing_service_;
bool was_last_shutdown_clean_; bool was_last_shutdown_clean_;
DISALLOW_COPY_AND_ASSIGN(ApplicationContextImpl); DISALLOW_COPY_AND_ASSIGN(ApplicationContextImpl);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "components/prefs/json_pref_store.h" #include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/rappor/rappor_service_impl.h" #include "components/rappor/rappor_service_impl.h"
#include "components/safe_browsing/core/features.h"
#include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_download_manager.h"
#include "components/ukm/ios/features.h" #include "components/ukm/ios/features.h"
#include "components/variations/field_trial_config/field_trial_util.h" #include "components/variations/field_trial_config/field_trial_util.h"
...@@ -45,6 +46,7 @@ ...@@ -45,6 +46,7 @@
#include "ios/chrome/browser/metrics/ios_expired_histograms_array.h" #include "ios/chrome/browser/metrics/ios_expired_histograms_array.h"
#include "ios/chrome/browser/open_from_clipboard/create_clipboard_recent_content.h" #include "ios/chrome/browser/open_from_clipboard/create_clipboard_recent_content.h"
#include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/pref_names.h"
#include "ios/chrome/browser/safe_browsing/safe_browsing_service.h"
#include "ios/chrome/browser/translate/translate_service_ios.h" #include "ios/chrome/browser/translate/translate_service_ios.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_task_traits.h"
...@@ -199,6 +201,17 @@ void IOSChromeMainParts::PreMainMessageLoopRun() { ...@@ -199,6 +201,17 @@ void IOSChromeMainParts::PreMainMessageLoopRun() {
last_used_browser_state->GetPrefs()); last_used_browser_state->GetPrefs());
variations_service->PerformPreMainMessageLoopStartup(); variations_service->PerformPreMainMessageLoopStartup();
} }
if (base::FeatureList::IsEnabled(
safe_browsing::kSafeBrowsingAvailableOnIOS)) {
// Ensure that Safe Browsing is initialized.
SafeBrowsingService* safe_browsing_service =
application_context_->GetSafeBrowsingService();
base::FilePath user_data_path;
CHECK(base::PathService::Get(ios::DIR_USER_DATA, &user_data_path));
safe_browsing_service->Initialize(last_used_browser_state->GetPrefs(),
user_data_path);
}
} }
void IOSChromeMainParts::PostMainMessageLoopRun() { void IOSChromeMainParts::PostMainMessageLoopRun() {
......
...@@ -55,6 +55,7 @@ source_set("browser_prefs") { ...@@ -55,6 +55,7 @@ source_set("browser_prefs") {
"//components/prefs", "//components/prefs",
"//components/proxy_config", "//components/proxy_config",
"//components/rappor", "//components/rappor",
"//components/safe_browsing/core/common:safe_browsing_prefs",
"//components/search_engines", "//components/search_engines",
"//components/sessions", "//components/sessions",
"//components/signin/public/identity_manager", "//components/signin/public/identity_manager",
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/rappor/rappor_service_impl.h" #include "components/rappor/rappor_service_impl.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/search_engines/template_url_prepopulate_data.h" #include "components/search_engines/template_url_prepopulate_data.h"
#include "components/sessions/core/session_id_generator.h" #include "components/sessions/core/session_id_generator.h"
#include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/base/signin_pref_names.h"
...@@ -157,6 +158,7 @@ void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { ...@@ -157,6 +158,7 @@ void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) {
payments::RegisterProfilePrefs(registry); payments::RegisterProfilePrefs(registry);
PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry); PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
RegisterVoiceSearchBrowserStatePrefs(registry); RegisterVoiceSearchBrowserStatePrefs(registry);
safe_browsing::RegisterProfilePrefs(registry);
sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry); sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
syncer::DeviceInfoPrefs::RegisterProfilePrefs(registry); syncer::DeviceInfoPrefs::RegisterProfilePrefs(registry);
syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry); syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
......
# Copyright 2020 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.
import("//ios/build/config.gni")
import("//ios/features.gni")
source_set("safe_browsing") {
sources = [
"safe_browsing_service.h",
"safe_browsing_service.mm",
]
deps = [
"//base",
"//build:branding_buildflags",
"//components/prefs",
"//components/safe_browsing/core/browser",
"//components/safe_browsing/core/common",
"//components/safe_browsing/core/db",
"//components/safe_browsing/core/db:v4_local_database_manager",
"//ios/net",
"//ios/web/public",
"//ios/web/public/init",
"//mojo/public/cpp/bindings",
"//services/network:network_service",
"//services/network/public/cpp",
"//services/network/public/mojom",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
source_set("unit_tests") {
testonly = true
sources = [ "safe_browsing_service_unittest.mm" ]
deps = [
":safe_browsing",
"//components/prefs:test_support",
"//components/safe_browsing/core/db",
"//components/safe_browsing/core/db:database_manager",
"//components/safe_browsing/core/db:metadata_proto",
"//components/safe_browsing/core/db:util",
"//components/safe_browsing/core/db:v4_database",
"//components/safe_browsing/core/db:v4_get_hash_protocol_manager",
"//components/safe_browsing/core/db:v4_protocol_manager_util",
"//components/safe_browsing/core/db:v4_test_util",
"//ios/web/public",
"//ios/web/public/test",
"//services/network/public/cpp",
"//testing/gtest",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SERVICE_H_
#define IOS_CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SERVICE_H_
#include "base/memory/ref_counted.h"
#include "ios/web/public/thread/web_thread.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/network_context.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
class PrefChangeRegistrar;
class PrefService;
namespace base {
class FilePath;
}
namespace net {
class URLRequestContext;
} // namespace net
namespace network {
class SharedURLLoaderFactory;
class WeakWrapperSharedURLLoaderFactory;
} // namespace network
namespace safe_browsing {
class SafeBrowsingDatabaseManager;
} // namespace safe_browsing
// Manages Safe Browsing related functionality. This class owns and provides
// support for constructing and initializing the Safe Browsing database. This
// class must be created and destroyed on the main thread. This class is
// RefCounted so that PostTask'd calls into this class can retain a reference
// to an instance.
class SafeBrowsingService
: public base::RefCountedThreadSafe<SafeBrowsingService,
web::WebThread::DeleteOnUIThread> {
public:
SafeBrowsingService();
// Called on the UI thread to initialize the service.
void Initialize(PrefService* prefs, const base::FilePath& user_data_path);
// Called on the UI thread to terminate the service. This must be called
// before the IO thread is torn down.
void ShutDown();
// Returns the SafeBrowsingDatabaseManager owned by this service.
safe_browsing::SafeBrowsingDatabaseManager* GetDatabaseManager();
private:
friend struct web::WebThread::DeleteOnThread<web::WebThread::UI>;
friend class base::DeleteHelper<SafeBrowsingService>;
// A helper class for enabling/disabling Safe Browsing and maintaining state
// on the IO thread. This class may be constructed and destroyed on the UI
// thread, but all of its other methods should only be called on the IO
// thread.
class IOThreadEnabler : public base::RefCountedThreadSafe<IOThreadEnabler> {
public:
IOThreadEnabler(scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
database_manager);
// Creates the network context and URL loader factory used by the
// SafeBrowsingDatabaseManager.
void Initialize(scoped_refptr<SafeBrowsingService> safe_browsing_service,
mojo::PendingReceiver<network::mojom::NetworkContext>
network_context_receiver);
// Disables Safe Browsing, and destroys the network context and URL loader
// factory used by the SafeBrowsingDatabaseManager.
void ShutDown();
// Enables or disables Safe Browsing database updates and lookups.
void SetSafeBrowsingEnabled(bool enabled);
private:
friend base::RefCountedThreadSafe<IOThreadEnabler>;
~IOThreadEnabler();
// Starts the SafeBrowsingDatabaseManager, making it ready to accept
// queries.
void StartSafeBrowsingDBManager();
// Constructs a URLRequestContext.
void SetUpURLRequestContext();
// Constructs a SharedURLLoaderFactory.
void SetUpURLLoaderFactory(
scoped_refptr<SafeBrowsingService> safe_browsing_service);
// This tracks whether the service is running.
bool enabled_ = false;
// This tracks whether ShutDown() has been called.
bool shutting_down_ = false;
// This is wrapped by |network_context|.
std::unique_ptr<net::URLRequestContext> url_request_context_;
// The network context used for Safe Browsing related network requests.
std::unique_ptr<network::NetworkContext> network_context_;
// An IO thread remote for a URLLoaderFactory created on the UI thread.
mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
// A SharedURLLoaderFactory that wraps |url_loader_factory_|.
scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
shared_url_loader_factory_;
// The database manager used for Safe Browsing queries.
scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
safe_browsing_db_manager_;
DISALLOW_COPY_AND_ASSIGN(IOThreadEnabler);
};
~SafeBrowsingService();
// Called on the UI thread to construct a URLLoaderFactory that is used on
// the IO thread.
void SetUpURLLoaderFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver);
// Enables or disables Safe Browsing, depending on the current state of
// preferences.
void UpdateSafeBrowsingEnabledState();
// This is the UI thread remote for IOThreadState's network context.
mojo::Remote<network::mojom::NetworkContext> network_context_client_;
// Constructed on the UI thread, but otherwise its methods are only called on
// the IO thread.
scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
safe_browsing_db_manager_;
// This watches for changes to the Safe Browsing opt-out preference.
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
// Encapsulates methods and objects that are used on the IO thread.
scoped_refptr<IOThreadEnabler> io_thread_enabler_;
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingService);
};
#endif // IOS_CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SERVICE_H_
// Copyright 2020 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 "ios/chrome/browser/safe_browsing/safe_browsing_service.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/task/post_task.h"
#include "build/branding_buildflags.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/browser/url_checker_delegate.h"
#include "components/safe_browsing/core/common/safebrowsing_constants.h"
#include "components/safe_browsing/core/db/v4_local_database_manager.h"
#include "ios/web/public/thread/web_task_traits.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#pragma mark - SafeBrowsingService
SafeBrowsingService::SafeBrowsingService() = default;
SafeBrowsingService::~SafeBrowsingService() = default;
void SafeBrowsingService::Initialize(PrefService* prefs,
const base::FilePath& user_data_path) {
DCHECK_CURRENTLY_ON(web::WebThread::UI);
if (io_thread_enabler_) {
// Already initialized.
return;
}
base::FilePath safe_browsing_data_path =
user_data_path.Append(safe_browsing::kSafeBrowsingBaseFilename);
safe_browsing_db_manager_ = safe_browsing::V4LocalDatabaseManager::Create(
safe_browsing_data_path, safe_browsing::ExtendedReportingLevelCallback());
io_thread_enabler_ =
base::MakeRefCounted<SafeBrowsingService::IOThreadEnabler>(
safe_browsing_db_manager_);
base::PostTask(
FROM_HERE, {web::WebThread::IO},
base::BindOnce(&SafeBrowsingService::IOThreadEnabler::Initialize,
io_thread_enabler_, base::WrapRefCounted(this),
network_context_client_.BindNewPipeAndPassReceiver()));
// Watch for changes to the Safe Browsing opt-out preference.
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(prefs);
pref_change_registrar_->Add(
prefs::kSafeBrowsingEnabled,
base::Bind(&SafeBrowsingService::UpdateSafeBrowsingEnabledState,
base::Unretained(this)));
UpdateSafeBrowsingEnabledState();
}
void SafeBrowsingService::ShutDown() {
DCHECK_CURRENTLY_ON(web::WebThread::UI);
pref_change_registrar_.reset();
base::PostTask(FROM_HERE, {web::WebThread::IO},
base::BindOnce(&SafeBrowsingService::IOThreadEnabler::ShutDown,
io_thread_enabler_));
network_context_client_.reset();
}
safe_browsing::SafeBrowsingDatabaseManager*
SafeBrowsingService::GetDatabaseManager() {
return safe_browsing_db_manager_.get();
}
void SafeBrowsingService::SetUpURLLoaderFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) {
DCHECK_CURRENTLY_ON(web::WebThread::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_client_->CreateURLLoaderFactory(
std::move(receiver), std::move(url_loader_factory_params));
}
void SafeBrowsingService::UpdateSafeBrowsingEnabledState() {
bool enabled =
pref_change_registrar_->prefs()->GetBoolean(prefs::kSafeBrowsingEnabled);
base::PostTask(
FROM_HERE, {web::WebThread::IO},
base::BindOnce(
&SafeBrowsingService::IOThreadEnabler::SetSafeBrowsingEnabled,
io_thread_enabler_, enabled));
}
#pragma mark - SafeBrowsingService::IOThreadEnabler
SafeBrowsingService::IOThreadEnabler::IOThreadEnabler(
scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager)
: safe_browsing_db_manager_(database_manager) {}
SafeBrowsingService::IOThreadEnabler::~IOThreadEnabler() = default;
void SafeBrowsingService::IOThreadEnabler::Initialize(
scoped_refptr<SafeBrowsingService> safe_browsing_service,
mojo::PendingReceiver<network::mojom::NetworkContext>
network_context_receiver) {
SetUpURLRequestContext();
std::vector<std::string> cors_exempt_header_list;
network_context_ = std::make_unique<network::NetworkContext>(
/*network_service=*/nullptr, std::move(network_context_receiver),
url_request_context_.get(), cors_exempt_header_list);
SetUpURLLoaderFactory(safe_browsing_service);
}
void SafeBrowsingService::IOThreadEnabler::ShutDown() {
DCHECK_CURRENTLY_ON(web::WebThread::IO);
shutting_down_ = true;
SetSafeBrowsingEnabled(false);
url_loader_factory_.reset();
network_context_.reset();
shared_url_loader_factory_.reset();
url_request_context_.reset();
}
void SafeBrowsingService::IOThreadEnabler::SetSafeBrowsingEnabled(
bool enabled) {
DCHECK_CURRENTLY_ON(web::WebThread::IO);
if (enabled_ == enabled)
return;
enabled_ = enabled;
if (enabled_)
StartSafeBrowsingDBManager();
else
safe_browsing_db_manager_->StopOnIOThread(shutting_down_);
}
void SafeBrowsingService::IOThreadEnabler::StartSafeBrowsingDBManager() {
DCHECK_CURRENTLY_ON(web::WebThread::IO);
std::string client_name;
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
client_name = "googlechrome";
#else
client_name = "chromium";
#endif
safe_browsing::V4ProtocolConfig config = safe_browsing::GetV4ProtocolConfig(
client_name, /*disable_auto_update=*/false);
safe_browsing_db_manager_->StartOnIOThread(shared_url_loader_factory_,
config);
}
void SafeBrowsingService::IOThreadEnabler::SetUpURLRequestContext() {
DCHECK_CURRENTLY_ON(web::WebThread::IO);
// This uses an in-memory non-persistent cookie store. The Safe Browsing V4
// Update API does not depend on cookies.
net::URLRequestContextBuilder builder;
url_request_context_ = builder.Build();
}
void SafeBrowsingService::IOThreadEnabler::SetUpURLLoaderFactory(
scoped_refptr<SafeBrowsingService> safe_browsing_service) {
DCHECK_CURRENTLY_ON(web::WebThread::IO);
base::PostTask(
FROM_HERE, {web::WebThread::UI},
base::BindOnce(&SafeBrowsingService::SetUpURLLoaderFactory,
safe_browsing_service,
url_loader_factory_.BindNewPipeAndPassReceiver()));
shared_url_loader_factory_ =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
url_loader_factory_.get());
}
// Copyright (c) 2020 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 "ios/chrome/browser/safe_browsing/safe_browsing_service.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "components/prefs/testing_pref_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/safe_browsing/core/db/database_manager.h"
#include "components/safe_browsing/core/db/metadata.pb.h"
#include "components/safe_browsing/core/db/util.h"
#include "components/safe_browsing/core/db/v4_database.h"
#include "components/safe_browsing/core/db/v4_get_hash_protocol_manager.h"
#include "components/safe_browsing/core/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/core/db/v4_test_util.h"
#include "ios/web/public/test/web_task_environment.h"
#include "ios/web/public/thread/web_task_traits.h"
#include "ios/web/public/thread/web_thread.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const char kSafePage[] = "http://example.test/safe.html";
const char kMalwarePage[] = "http://example.test/malware.html";
class TestSBClient : public base::RefCountedThreadSafe<TestSBClient>,
public safe_browsing::SafeBrowsingDatabaseManager::Client {
public:
TestSBClient(SafeBrowsingService* safe_browsing_service)
: result_pending_(false),
threat_type_(safe_browsing::SB_THREAT_TYPE_SAFE),
safe_browsing_service_(safe_browsing_service) {}
safe_browsing::SBThreatType threat_type() const { return threat_type_; }
std::string threat_hash() const { return threat_hash_; }
void CheckUrl(const GURL& url) {
result_pending_ = true;
base::PostTask(
FROM_HERE, {web::WebThread::IO},
base::BindOnce(&TestSBClient::CheckBrowseUrlOnIOThread, this, url));
}
bool result_pending() const { return result_pending_; }
void WaitForResult() {
while (result_pending()) {
base::RunLoop().RunUntilIdle();
}
}
private:
friend class base::RefCountedThreadSafe<TestSBClient>;
~TestSBClient() override {}
void CheckBrowseUrlOnIOThread(const GURL& url) {
safe_browsing::SBThreatTypeSet threat_types =
safe_browsing::CreateSBThreatTypeSet(
{safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
safe_browsing::SB_THREAT_TYPE_URL_UNWANTED,
safe_browsing::SB_THREAT_TYPE_BILLING});
// The async CheckDone() hook will not be called when we have a synchronous
// safe signal, so call it right away.
bool synchronous_safe_signal =
safe_browsing_service_->GetDatabaseManager()->CheckBrowseUrl(
url, threat_types, this);
if (synchronous_safe_signal) {
threat_type_ = safe_browsing::SB_THREAT_TYPE_SAFE;
base::PostTask(FROM_HERE, {web::WebThread::UI},
base::BindOnce(&TestSBClient::CheckDone, this));
}
}
void OnCheckBrowseUrlResult(
const GURL& url,
safe_browsing::SBThreatType threat_type,
const safe_browsing::ThreatMetadata& metadata) override {
threat_type_ = threat_type;
base::PostTask(FROM_HERE, {web::WebThread::UI},
base::BindOnce(&TestSBClient::CheckDone, this));
}
void CheckDone() { result_pending_ = false; }
bool result_pending_;
safe_browsing::SBThreatType threat_type_;
std::string threat_hash_;
SafeBrowsingService* safe_browsing_service_;
DISALLOW_COPY_AND_ASSIGN(TestSBClient);
};
} // namespace
class SafeBrowsingServiceTest : public PlatformTest {
public:
SafeBrowsingServiceTest() {
safe_browsing::RegisterProfilePrefs(local_state_.registry());
store_factory_ = new safe_browsing::TestV4StoreFactory();
safe_browsing::V4Database::RegisterStoreFactoryForTest(
base::WrapUnique(store_factory_));
v4_db_factory_ = new safe_browsing::TestV4DatabaseFactory();
safe_browsing::V4Database::RegisterDatabaseFactoryForTest(
base::WrapUnique(v4_db_factory_));
v4_get_hash_factory_ =
new safe_browsing::TestV4GetHashProtocolManagerFactory();
safe_browsing::V4GetHashProtocolManager::RegisterFactory(
base::WrapUnique(v4_get_hash_factory_));
safe_browsing_service_ = base::MakeRefCounted<SafeBrowsingService>();
CHECK(temp_dir_.CreateUniqueTempDir());
safe_browsing_service_->Initialize(&local_state_, temp_dir_.GetPath());
base::RunLoop().RunUntilIdle();
}
~SafeBrowsingServiceTest() override {
safe_browsing_service_->ShutDown();
safe_browsing::V4GetHashProtocolManager::RegisterFactory(nullptr);
safe_browsing::V4Database::RegisterDatabaseFactoryForTest(nullptr);
safe_browsing::V4Database::RegisterStoreFactoryForTest(nullptr);
}
void MarkUrlAsMalware(const GURL& bad_url) {
base::PostTask(
FROM_HERE, {web::WebThread::IO},
base::BindOnce(&SafeBrowsingServiceTest::MarkUrlAsMalwareOnIOThread,
base::Unretained(this), bad_url));
}
protected:
web::WebTaskEnvironment task_environment_;
TestingPrefServiceSimple local_state_;
scoped_refptr<SafeBrowsingService> safe_browsing_service_;
private:
void MarkUrlAsMalwareOnIOThread(const GURL& bad_url) {
safe_browsing::FullHashInfo full_hash_info =
safe_browsing::GetFullHashInfoWithMetadata(
bad_url, safe_browsing::GetUrlMalwareId(),
safe_browsing::ThreatMetadata());
v4_db_factory_->MarkPrefixAsBad(safe_browsing::GetUrlMalwareId(),
full_hash_info.full_hash);
v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
}
base::ScopedTempDir temp_dir_;
// Owned by V4Database.
safe_browsing::TestV4DatabaseFactory* v4_db_factory_;
// Owned by V4GetHashProtocolManager.
safe_browsing::TestV4GetHashProtocolManagerFactory* v4_get_hash_factory_;
// Owned by V4Database.
safe_browsing::TestV4StoreFactory* store_factory_;
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
};
TEST_F(SafeBrowsingServiceTest, SafeAndUnsafePages) {
// Verify that queries to the Safe Browsing database owned by
// SafeBrowsignServiceIOSImpl receive respones.
scoped_refptr<TestSBClient> client =
base::MakeRefCounted<TestSBClient>(safe_browsing_service_.get());
GURL safe_url = GURL(kSafePage);
client->CheckUrl(safe_url);
EXPECT_TRUE(client->result_pending());
client->WaitForResult();
EXPECT_FALSE(client->result_pending());
EXPECT_EQ(client->threat_type(), safe_browsing::SB_THREAT_TYPE_SAFE);
GURL unsafe_url = GURL(kMalwarePage);
MarkUrlAsMalware(unsafe_url);
client->CheckUrl(unsafe_url);
EXPECT_TRUE(client->result_pending());
client->WaitForResult();
EXPECT_FALSE(client->result_pending());
EXPECT_EQ(client->threat_type(), safe_browsing::SB_THREAT_TYPE_URL_MALWARE);
// Disable Safe Browsing, and ensure that unsafe URLs are no longer flagged.
local_state_.SetUserPref(prefs::kSafeBrowsingEnabled,
std::make_unique<base::Value>(false));
client->CheckUrl(unsafe_url);
EXPECT_TRUE(client->result_pending());
client->WaitForResult();
EXPECT_FALSE(client->result_pending());
EXPECT_EQ(client->threat_type(), safe_browsing::SB_THREAT_TYPE_SAFE);
}
...@@ -207,6 +207,7 @@ test("ios_chrome_unittests") { ...@@ -207,6 +207,7 @@ test("ios_chrome_unittests") {
"//ios/chrome/browser/passwords:unit_tests", "//ios/chrome/browser/passwords:unit_tests",
"//ios/chrome/browser/prerender:unit_tests", "//ios/chrome/browser/prerender:unit_tests",
"//ios/chrome/browser/reading_list:unit_tests", "//ios/chrome/browser/reading_list:unit_tests",
"//ios/chrome/browser/safe_browsing:unit_tests",
"//ios/chrome/browser/safe_mode:unit_tests", "//ios/chrome/browser/safe_mode:unit_tests",
"//ios/chrome/browser/search_engines:unit_tests", "//ios/chrome/browser/search_engines:unit_tests",
"//ios/chrome/browser/send_tab_to_self:unit_tests", "//ios/chrome/browser/send_tab_to_self:unit_tests",
......
...@@ -60,6 +60,7 @@ class TestingApplicationContext : public ApplicationContext { ...@@ -60,6 +60,7 @@ class TestingApplicationContext : public ApplicationContext {
gcm::GCMDriver* GetGCMDriver() override; gcm::GCMDriver* GetGCMDriver() override;
component_updater::ComponentUpdateService* GetComponentUpdateService() component_updater::ComponentUpdateService* GetComponentUpdateService()
override; override;
SafeBrowsingService* GetSafeBrowsingService() override;
network::NetworkConnectionTracker* GetNetworkConnectionTracker() override; network::NetworkConnectionTracker* GetNetworkConnectionTracker() override;
BrowserPolicyConnectorIOS* GetBrowserPolicyConnector() override; BrowserPolicyConnectorIOS* GetBrowserPolicyConnector() override;
......
...@@ -184,6 +184,11 @@ TestingApplicationContext::GetComponentUpdateService() { ...@@ -184,6 +184,11 @@ TestingApplicationContext::GetComponentUpdateService() {
return nullptr; return nullptr;
} }
SafeBrowsingService* TestingApplicationContext::GetSafeBrowsingService() {
DCHECK(thread_checker_.CalledOnValidThread());
return nullptr;
}
network::NetworkConnectionTracker* network::NetworkConnectionTracker*
TestingApplicationContext::GetNetworkConnectionTracker() { TestingApplicationContext::GetNetworkConnectionTracker() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
......
...@@ -52,11 +52,6 @@ extern const base::Feature kUseDefaultUserAgentInWebClient; ...@@ -52,11 +52,6 @@ extern const base::Feature kUseDefaultUserAgentInWebClient;
// of properties using hard coded logic. // of properties using hard coded logic.
extern const base::Feature kPreserveScrollViewProperties; extern const base::Feature kPreserveScrollViewProperties;
// Feature flag for making native (instead of WKWebView-provided) Safe
// Browsing available. When this flag is enabled, Safe Browsing is still
// subject to an opt-out controlled by prefs::kSafeBrowsingEnabled.
extern const base::Feature kSafeBrowsingAvailable;
// Level at which battery power is considered low, and some cosmetic features // Level at which battery power is considered low, and some cosmetic features
// can be turned off. // can be turned off.
const float kLowBatteryLevelThreshold = 0.2; const float kLowBatteryLevelThreshold = 0.2;
......
...@@ -44,8 +44,5 @@ const base::Feature kUseDefaultUserAgentInWebClient{ ...@@ -44,8 +44,5 @@ const base::Feature kUseDefaultUserAgentInWebClient{
const base::Feature kPreserveScrollViewProperties{ const base::Feature kPreserveScrollViewProperties{
"PreserveScrollViewProperties", base::FEATURE_DISABLED_BY_DEFAULT}; "PreserveScrollViewProperties", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kSafeBrowsingAvailable{"SafeBrowsingAvailable",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features } // namespace features
} // namespace web } // namespace web
...@@ -115,6 +115,7 @@ source_set("crw_context_menu_controller") { ...@@ -115,6 +115,7 @@ source_set("crw_context_menu_controller") {
source_set("wk_web_view_configuration_provider") { source_set("wk_web_view_configuration_provider") {
deps = [ deps = [
"//base", "//base",
"//components/safe_browsing/core:features",
"//ios/third_party/webkit", "//ios/third_party/webkit",
"//ios/web/common", "//ios/web/common",
"//ios/web/js_messaging", "//ios/web/js_messaging",
......
include_rules = [
"+components/safe_browsing/core/features.h"
]
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "components/safe_browsing/core/features.h"
#include "ios/web/common/features.h" #include "ios/web/common/features.h"
#import "ios/web/js_messaging/crw_wk_script_message_router.h" #import "ios/web/js_messaging/crw_wk_script_message_router.h"
#import "ios/web/js_messaging/page_script_util.h" #import "ios/web/js_messaging/page_script_util.h"
...@@ -135,7 +136,8 @@ void WKWebViewConfigurationProvider::ResetWithWebViewConfiguration( ...@@ -135,7 +136,8 @@ void WKWebViewConfigurationProvider::ResetWithWebViewConfiguration(
// conceptually similar to Safe Browsing but uses a non-Google provider and // conceptually similar to Safe Browsing but uses a non-Google provider and
// only works for devices in certain locales. Disable this feature when // only works for devices in certain locales. Disable this feature when
// Safe Browsing is available. // Safe Browsing is available.
if (base::FeatureList::IsEnabled(web::features::kSafeBrowsingAvailable)) { if (base::FeatureList::IsEnabled(
safe_browsing::kSafeBrowsingAvailableOnIOS)) {
[[configuration_ preferences] setFraudulentWebsiteWarningEnabled:NO]; [[configuration_ preferences] setFraudulentWebsiteWarningEnabled:NO];
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment