blob: b5eb1b9afc0acfe461fe5b79eeb7d1e9df2636e3 [file] [log] [blame]
// Copyright 2016 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.
// This file should not be build on Android but is currently getting built.
// TODO(vakh): Fix that: http://crbug.com/621647
#include "components/safe_browsing_db/v4_local_database_manager.h"
#include <vector>
#include "base/callback.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace safe_browsing {
namespace {
// TODO(vakh): Implement this to populate the map appopriately.
// Filed as http://crbug.com/608075
StoreFileNameMap GetStoreFileNameMap() {
return StoreFileNameMap({{GetUrlMalwareId(), "UrlMalware.store"},
{GetUrlSocEngId(), "UrlSoceng.store"}});
}
} // namespace
V4LocalDatabaseManager::V4LocalDatabaseManager(const base::FilePath& base_path)
: base_path_(base_path), enabled_(false) {
DCHECK(!base_path_.empty());
DVLOG(1) << "V4LocalDatabaseManager::V4LocalDatabaseManager: "
<< "base_path_: " << base_path_.AsUTF8Unsafe();
}
V4LocalDatabaseManager::~V4LocalDatabaseManager() {
DCHECK(!enabled_);
}
bool V4LocalDatabaseManager::IsSupported() const {
return true;
}
ThreatSource V4LocalDatabaseManager::GetThreatSource() const {
return ThreatSource::LOCAL_PVER4;
}
bool V4LocalDatabaseManager::ChecksAreAlwaysAsync() const {
return false;
}
bool V4LocalDatabaseManager::CanCheckResourceType(
content::ResourceType resource_type) const {
// We check all types since most checks are fast.
return true;
}
bool V4LocalDatabaseManager::CanCheckUrl(const GURL& url) const {
return url.SchemeIs(url::kHttpsScheme) || url.SchemeIs(url::kHttpScheme) ||
url.SchemeIs(url::kFtpScheme);
}
bool V4LocalDatabaseManager::IsDownloadProtectionEnabled() const {
// TODO(vakh): Investigate the possibility of using a command line switch for
// this instead.
return true;
}
bool V4LocalDatabaseManager::CheckDownloadUrl(
const std::vector<GURL>& url_chain,
Client* client) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// TODO(vakh): Implement this skeleton.
return true;
}
bool V4LocalDatabaseManager::CheckExtensionIDs(
const std::set<std::string>& extension_ids,
Client* client) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::MatchMalwareIP(const std::string& ip_address) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return false;
}
bool V4LocalDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::MatchDownloadWhitelistString(
const std::string& str) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::MatchModuleWhitelistString(
const std::string& str) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::CheckResourceUrl(const GURL& url, Client* client) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::IsMalwareKillSwitchOn() {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::IsCsdWhitelistKillSwitchOn() {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
bool V4LocalDatabaseManager::CheckBrowseUrl(const GURL& url, Client* client) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!enabled_ || !CanCheckUrl(url)) {
return true;
}
if (v4_database_) {
base::hash_set<FullHash> full_hashes;
V4ProtocolManagerUtil::UrlToFullHashes(url, &full_hashes);
base::hash_set<UpdateListIdentifier> stores_to_look(
{GetUrlMalwareId(), GetUrlSocEngId()});
base::hash_set<HashPrefix> matched_hash_prefixes;
base::hash_set<UpdateListIdentifier> matched_stores;
MatchedHashPrefixMap matched_hash_prefix_map;
for (const auto& full_hash : full_hashes) {
v4_database_->GetStoresMatchingFullHash(full_hash, stores_to_look,
&matched_hash_prefix_map);
for (const auto& matched_pair : matched_hash_prefix_map) {
matched_stores.insert(matched_pair.first);
matched_hash_prefixes.insert(matched_pair.second);
}
}
DCHECK_EQ(matched_stores.empty(), matched_hash_prefixes.empty());
// TODO(vakh): Return false and fetch full hashes for the matching hash
// prefixes.
return matched_hash_prefixes.empty();
} else {
// TODO(vakh): Queue the check and process it when the database becomes
// ready.
return false;
}
}
void V4LocalDatabaseManager::CancelCheck(Client* client) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(enabled_);
}
void V4LocalDatabaseManager::StartOnIOThread(
net::URLRequestContextGetter* request_context_getter,
const V4ProtocolConfig& config) {
SafeBrowsingDatabaseManager::StartOnIOThread(request_context_getter, config);
db_updated_callback_ = base::Bind(&V4LocalDatabaseManager::DatabaseUpdated,
base::Unretained(this));
SetupUpdateProtocolManager(request_context_getter, config);
SetupDatabase();
enabled_ = true;
}
void V4LocalDatabaseManager::SetupUpdateProtocolManager(
net::URLRequestContextGetter* request_context_getter,
const V4ProtocolConfig& config) {
V4UpdateCallback callback = base::Bind(
&V4LocalDatabaseManager::UpdateRequestCompleted, base::Unretained(this));
v4_update_protocol_manager_ =
V4UpdateProtocolManager::Create(request_context_getter, config, callback);
}
void V4LocalDatabaseManager::SetupDatabase() {
DCHECK(!base_path_.empty());
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Only get a new task runner if there isn't one already. If the service has
// previously been started and stopped, a task runner could already exist.
if (!task_runner_) {
base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
}
// Do not create the database on the IO thread since this may be an expensive
// operation. Instead, do that on the task_runner and when the new database
// has been created, swap it out on the IO thread.
StoreFileNameMap store_file_name_map = GetStoreFileNameMap();
DCHECK(!store_file_name_map.empty());
NewDatabaseReadyCallback db_ready_callback = base::Bind(
&V4LocalDatabaseManager::DatabaseReady, base::Unretained(this));
V4Database::Create(task_runner_, base_path_, store_file_name_map,
db_ready_callback);
}
void V4LocalDatabaseManager::DatabaseReady(
std::unique_ptr<V4Database> v4_database) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// The following check is needed because it is possible that by the time the
// database is ready, StopOnIOThread has been called.
if (enabled_) {
v4_database_ = std::move(v4_database);
// The database is in place. Start fetching updates now.
v4_update_protocol_manager_->ScheduleNextUpdate(
v4_database_->GetStoreStateMap());
} else {
// Schedule the deletion of v4_database off IO thread.
V4Database::Destroy(std::move(v4_database));
}
}
void V4LocalDatabaseManager::StopOnIOThread(bool shutdown) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
enabled_ = false;
// Delete the V4Database. Any pending writes to disk are completed.
// This operation happens on the task_runner on which v4_database_ operates
// and doesn't block the IO thread.
V4Database::Destroy(std::move(v4_database_));
// Delete the V4UpdateProtocolManager.
// This cancels any in-flight update request.
v4_update_protocol_manager_.reset();
db_updated_callback_.Reset();
SafeBrowsingDatabaseManager::StopOnIOThread(shutdown);
}
void V4LocalDatabaseManager::UpdateRequestCompleted(
std::unique_ptr<ParsedServerResponse> parsed_server_response) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
v4_database_->ApplyUpdate(std::move(parsed_server_response),
db_updated_callback_);
}
void V4LocalDatabaseManager::DatabaseUpdated() {
if (enabled_) {
v4_update_protocol_manager_->ScheduleNextUpdate(
v4_database_->GetStoreStateMap());
}
}
} // namespace safe_browsing