blob: cf6aff3ba65ee218a4e01b15ec6045c40e304125 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/safe_browsing/core/browser/hash_realtime_mechanism.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/sequenced_task_runner.h"
#include "components/safe_browsing/core/browser/db/database_manager.h"
#include "components/safe_browsing/core/browser/db/util.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/core/browser/safe_browsing_lookup_mechanism.h"
namespace safe_browsing {
HashRealTimeMechanism::HashRealTimeMechanism(
const GURL& url,
const SBThreatTypeSet& threat_types,
scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
bool can_check_db,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
base::WeakPtr<HashRealTimeService> lookup_service_on_ui)
: SafeBrowsingLookupMechanism(url,
threat_types,
database_manager,
can_check_db),
ui_task_runner_(ui_task_runner),
lookup_service_on_ui_(lookup_service_on_ui) {}
HashRealTimeMechanism::~HashRealTimeMechanism() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
SafeBrowsingLookupMechanism::StartCheckResult
HashRealTimeMechanism::StartCheckInternal() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!can_check_db_) {
return StartCheckResult(
/*is_safe_synchronously=*/true,
/*did_check_url_real_time_allowlist=*/false);
}
bool has_allowlist_match =
database_manager_->CheckUrlForHighConfidenceAllowlist(url_, "HPRT");
base::UmaHistogramEnumeration(
"SafeBrowsing.HPRT.LocalMatch.Result",
has_allowlist_match ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH);
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&HashRealTimeMechanism::OnCheckUrlForHighConfidenceAllowlist,
weak_factory_.GetWeakPtr(),
/*did_match_allowlist=*/has_allowlist_match));
return StartCheckResult(
/*is_safe_synchronously=*/false,
/*did_check_url_real_time_allowlist=*/false);
}
void HashRealTimeMechanism::OnCheckUrlForHighConfidenceAllowlist(
bool did_match_allowlist) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (did_match_allowlist) {
// If the URL matches the high-confidence allowlist, still do the hash based
// checks.
PerformHashBasedCheck(url_);
} else {
ui_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&HashRealTimeMechanism::StartLookupOnUIThread,
weak_factory_.GetWeakPtr(), url_, lookup_service_on_ui_,
base::SequencedTaskRunner::GetCurrentDefault()));
}
}
// static
void HashRealTimeMechanism::StartLookupOnUIThread(
base::WeakPtr<HashRealTimeMechanism> weak_ptr_on_io,
const GURL& url,
base::WeakPtr<HashRealTimeService> lookup_service_on_ui,
scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
bool is_lookup_service_available =
lookup_service_on_ui && !lookup_service_on_ui->IsInBackoffMode();
base::UmaHistogramBoolean("SafeBrowsing.HPRT.IsLookupServiceAvailable",
is_lookup_service_available);
if (!is_lookup_service_available) {
io_task_runner->PostTask(
FROM_HERE, base::BindOnce(&HashRealTimeMechanism::PerformHashBasedCheck,
weak_ptr_on_io, url));
return;
}
HPRTLookupResponseCallback response_callback =
base::BindOnce(&HashRealTimeMechanism::OnLookupResponse, weak_ptr_on_io);
lookup_service_on_ui->StartLookup(url, std::move(response_callback),
std::move(io_task_runner));
}
void HashRealTimeMechanism::OnLookupResponse(
bool is_lookup_successful,
absl::optional<SBThreatType> threat_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_lookup_successful) {
PerformHashBasedCheck(url_);
return;
}
DCHECK(threat_type.has_value());
CompleteCheck(std::make_unique<CompleteCheckResult>(
url_, threat_type.value(), ThreatMetadata(),
/*is_from_url_real_time_check=*/false,
/*url_real_time_lookup_response=*/nullptr));
}
void HashRealTimeMechanism::PerformHashBasedCheck(const GURL& url) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
hash_database_mechanism_ = std::make_unique<HashDatabaseMechanism>(
url, threat_types_, database_manager_, can_check_db_);
auto result = hash_database_mechanism_->StartCheck(
base::BindOnce(&HashRealTimeMechanism::OnHashDatabaseCompleteCheckResult,
weak_factory_.GetWeakPtr()));
if (result.is_safe_synchronously) {
// No match found in the database, so conclude this is safe.
OnHashDatabaseCompleteCheckResultInternal(SB_THREAT_TYPE_SAFE,
ThreatMetadata());
}
}
void HashRealTimeMechanism::OnHashDatabaseCompleteCheckResult(
std::unique_ptr<SafeBrowsingLookupMechanism::CompleteCheckResult> result) {
OnHashDatabaseCompleteCheckResultInternal(result->threat_type,
result->metadata);
}
void HashRealTimeMechanism::OnHashDatabaseCompleteCheckResultInternal(
SBThreatType threat_type,
const ThreatMetadata& metadata) {
CompleteCheck(std::make_unique<CompleteCheckResult>(
url_, threat_type, metadata,
/*is_from_url_real_time_check=*/false,
/*url_real_time_lookup_response=*/nullptr));
}
} // namespace safe_browsing