summaryrefslogtreecommitdiff
path: root/chromium/components/safe_browsing/content
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/safe_browsing/content')
-rw-r--r--chromium/components/safe_browsing/content/base_blocking_page.cc4
-rw-r--r--chromium/components/safe_browsing/content/base_blocking_page.h2
-rw-r--r--chromium/components/safe_browsing/content/base_ui_manager.cc64
-rw-r--r--chromium/components/safe_browsing/content/browser/BUILD.gn2
-rw-r--r--chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc60
-rw-r--r--chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.h6
-rw-r--r--chromium/components/safe_browsing/content/browser/mojo_safe_browsing_impl.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_url_checker_impl_content.cc13
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details.cc9
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_cache.cc11
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_history.cc7
-rw-r--r--chromium/components/safe_browsing/content/common/safe_browsing.mojom13
-rw-r--r--chromium/components/safe_browsing/content/password_protection/BUILD.gn3
-rw-r--r--chromium/components/safe_browsing/content/password_protection/DEPS3
-rw-r--r--chromium/components/safe_browsing/content/password_protection/metrics_util.cc1
-rw-r--r--chromium/components/safe_browsing/content/password_protection/mock_password_protection_service.h17
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_request.cc15
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_service.cc65
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_service.h33
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc36
-rw-r--r--chromium/components/safe_browsing/content/password_protection/visual_utils.cc182
-rw-r--r--chromium/components/safe_browsing/content/password_protection/visual_utils.h10
-rw-r--r--chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc259
-rw-r--r--chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc38
-rw-r--r--chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.h20
-rw-r--r--chromium/components/safe_browsing/content/triggers/ad_popup_trigger.cc4
-rw-r--r--chromium/components/safe_browsing/content/triggers/ad_redirect_trigger.cc4
-rw-r--r--chromium/components/safe_browsing/content/triggers/ad_sampler_trigger.cc4
-rw-r--r--chromium/components/safe_browsing/content/triggers/suspicious_site_trigger.cc4
-rw-r--r--chromium/components/safe_browsing/content/web_ui/BUILD.gn1
-rw-r--r--chromium/components/safe_browsing/content/web_ui/DEPS1
-rw-r--r--chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.css25
-rw-r--r--chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html28
-rw-r--r--chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js77
-rw-r--r--chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc187
-rw-r--r--chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h11
36 files changed, 941 insertions, 282 deletions
diff --git a/chromium/components/safe_browsing/content/base_blocking_page.cc b/chromium/components/safe_browsing/content/base_blocking_page.cc
index 513ed5b08f7..bc7d4dc3c7d 100644
--- a/chromium/components/safe_browsing/content/base_blocking_page.cc
+++ b/chromium/components/safe_browsing/content/base_blocking_page.cc
@@ -138,10 +138,6 @@ void BaseBlockingPage::PopulateInterstitialStrings(
sb_error_ui_->PopulateStringsForHtml(load_time_data);
}
-void BaseBlockingPage::OnInterstitialClosing() {
- UpdateMetricsAfterSecurityInterstitial();
-}
-
void BaseBlockingPage::FinishThreatDetails(const base::TimeDelta& delay,
bool did_proceed,
int num_visits) {}
diff --git a/chromium/components/safe_browsing/content/base_blocking_page.h b/chromium/components/safe_browsing/content/base_blocking_page.h
index 1e35a434363..97bfb779040 100644
--- a/chromium/components/safe_browsing/content/base_blocking_page.h
+++ b/chromium/components/safe_browsing/content/base_blocking_page.h
@@ -61,7 +61,7 @@ class BaseBlockingPage
bool ShouldCreateNewNavigation() const override;
void PopulateInterstitialStrings(
base::DictionaryValue* load_time_data) override;
- void OnInterstitialClosing() override;
+ void OnInterstitialClosing() override {}
// Called when the interstitial is going away. Intentionally do nothing in
// this base class.
diff --git a/chromium/components/safe_browsing/content/base_ui_manager.cc b/chromium/components/safe_browsing/content/base_ui_manager.cc
index 6643359fd2e..680b1098f46 100644
--- a/chromium/components/safe_browsing/content/base_ui_manager.cc
+++ b/chromium/components/safe_browsing/content/base_ui_manager.cc
@@ -190,6 +190,21 @@ void BaseUIManager::OnBlockingPageDone(
}
}
+namespace {
+// In the case of nested WebContents, returns the WebContents where it is
+// suitable to show an interstitial.
+content::WebContents* GetEmbeddingWebContentsForInterstitial(
+ content::WebContents* source_contents) {
+ content::WebContents* top_level_contents = source_contents;
+ // Note that |WebContents::GetResponsibleWebContents| is not suitable here
+ // since we want to stay within any GuestViews.
+ while (top_level_contents->IsPortal()) {
+ top_level_contents = top_level_contents->GetPortalHostWebContents();
+ }
+ return top_level_contents;
+}
+} // namespace
+
void BaseUIManager::DisplayBlockingPage(
const UnsafeResource& resource) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -245,13 +260,26 @@ void BaseUIManager::DisplayBlockingPage(
}
AddToWhitelistUrlSet(GetMainFrameWhitelistUrlForResource(resource),
- resource.web_contents_getter.Run(),
- true /* A decision is now pending */,
+ web_contents, true /* A decision is now pending */,
resource.threat_type);
- GURL unsafe_url = (resource.IsMainPageLoadBlocked() ||
- !GetNavigationEntryForResource(resource))
- ? resource.url
- : GetNavigationEntryForResource(resource)->GetURL();
+
+ // |entry| can be null if we are on a brand new tab, and a resource is added
+ // via javascript without a navigation.
+ content::NavigationEntry* entry = GetNavigationEntryForResource(resource);
+
+ // If unsafe content is loaded in a portal, we treat its embedder as
+ // dangerous.
+ content::WebContents* outermost_contents =
+ GetEmbeddingWebContentsForInterstitial(web_contents);
+
+ GURL unsafe_url = resource.url;
+ if (outermost_contents != web_contents) {
+ DCHECK(outermost_contents->GetController().GetLastCommittedEntry());
+ unsafe_url =
+ outermost_contents->GetController().GetLastCommittedEntry()->GetURL();
+ } else if (entry && !resource.IsMainPageLoadBlocked()) {
+ unsafe_url = entry->GetURL();
+ }
AddUnsafeResource(unsafe_url, resource);
// If the delayed warnings experiment is not enabled, with committed
// interstitials we just cancel the load from here, the actual interstitial
@@ -273,28 +301,24 @@ void BaseUIManager::DisplayBlockingPage(
DCHECK(!resource.is_delayed_warning);
}
- if ((!resource.IsMainPageLoadBlocked() || resource.is_delayed_warning) &&
- !IsWhitelisted(resource)) {
+ if (!resource.IsMainPageLoadBlocked() || resource.is_delayed_warning ||
+ outermost_contents != web_contents) {
+ DCHECK(!IsWhitelisted(resource));
// For subresource triggered interstitials, we trigger the error page
// navigation from here since there will be no navigation to intercept
// in the throttle.
- content::WebContents* contents = resource.web_contents_getter.Run();
- content::NavigationEntry* entry = GetNavigationEntryForResource(resource);
- // entry can be null if we are on a brand new tab, and a resource is added
- // via javascript without a navigation.
- GURL blocked_url = entry ? entry->GetURL() : resource.url;
-
+ //
// Blocking pages handle both user interaction, and generation of the
// interstitial HTML. In the case of subresources, we need the HTML
// content prior to (and in a different process than when) installing the
// command handlers. For this reason we create a blocking page here just
// to generate the HTML, and immediately delete it.
- BaseBlockingPage* blocking_page =
- CreateBlockingPageForSubresource(contents, blocked_url, resource);
- contents->GetController().LoadPostCommitErrorPage(
- contents->GetMainFrame(), blocked_url, blocking_page->GetHTMLContents(),
- net::ERR_BLOCKED_BY_CLIENT);
- delete blocking_page;
+ std::unique_ptr<BaseBlockingPage> blocking_page =
+ base::WrapUnique(CreateBlockingPageForSubresource(
+ outermost_contents, unsafe_url, resource));
+ outermost_contents->GetController().LoadPostCommitErrorPage(
+ outermost_contents->GetMainFrame(), unsafe_url,
+ blocking_page->GetHTMLContents(), net::ERR_BLOCKED_BY_CLIENT);
}
}
diff --git a/chromium/components/safe_browsing/content/browser/BUILD.gn b/chromium/components/safe_browsing/content/browser/BUILD.gn
index 6111969ed2b..0b942f26ce3 100644
--- a/chromium/components/safe_browsing/content/browser/BUILD.gn
+++ b/chromium/components/safe_browsing/content/browser/BUILD.gn
@@ -33,7 +33,7 @@ jumbo_source_set("browser") {
"//components/safe_browsing/core/common:common",
"//components/safe_browsing/core/db:database_manager",
"//components/safe_browsing/core/realtime:policy_engine",
- "//components/safe_browsing/core/realtime:url_lookup_service",
+ "//components/safe_browsing/core/realtime:url_lookup_service_base",
"//components/safe_browsing/core/web_ui:constants",
"//components/security_interstitials/content:security_interstitial_page",
"//components/security_interstitials/core:unsafe_resource",
diff --git a/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc b/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc
index cb3aa4a82be..2fa3d9cc4c9 100644
--- a/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc
+++ b/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc
@@ -13,7 +13,7 @@
#include "components/safe_browsing/core/common/safebrowsing_constants.h"
#include "components/safe_browsing/core/common/utils.h"
#include "components/safe_browsing/core/realtime/policy_engine.h"
-#include "components/safe_browsing/core/realtime/url_lookup_service.h"
+#include "components/safe_browsing/core/realtime/url_lookup_service_base.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/web_contents.h"
#include "net/log/net_log_event_type.h"
@@ -34,14 +34,16 @@ class BrowserURLLoaderThrottle::CheckerOnIO
base::RepeatingCallback<content::WebContents*()> web_contents_getter,
base::WeakPtr<BrowserURLLoaderThrottle> throttle,
bool real_time_lookup_enabled,
- bool enhanced_protection_enabled,
- base::WeakPtr<RealTimeUrlLookupService> url_lookup_service)
+ bool can_rt_check_subresource_url,
+ bool can_check_db,
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service)
: delegate_getter_(std::move(delegate_getter)),
frame_tree_node_id_(frame_tree_node_id),
web_contents_getter_(web_contents_getter),
throttle_(std::move(throttle)),
real_time_lookup_enabled_(real_time_lookup_enabled),
- enhanced_protection_enabled_(enhanced_protection_enabled),
+ can_rt_check_subresource_url_(can_rt_check_subresource_url),
+ can_check_db_(can_check_db),
url_lookup_service_(url_lookup_service) {}
// Starts the initial safe browsing check. This check and future checks may be
@@ -63,8 +65,8 @@ class BrowserURLLoaderThrottle::CheckerOnIO
url, frame_tree_node_id_, -1 /* render_process_id */,
-1 /* render_frame_id */, originated_from_service_worker);
if (skip_checks_) {
- base::PostTask(
- FROM_HERE, {content::BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&BrowserURLLoaderThrottle::SkipChecks, throttle_));
return;
}
@@ -72,7 +74,7 @@ class BrowserURLLoaderThrottle::CheckerOnIO
url_checker_ = std::make_unique<SafeBrowsingUrlCheckerImpl>(
headers, load_flags, resource_type, has_user_gesture,
url_checker_delegate, web_contents_getter_, real_time_lookup_enabled_,
- enhanced_protection_enabled_, url_lookup_service_);
+ can_rt_check_subresource_url_, can_check_db_, url_lookup_service_);
CheckUrl(url, method);
}
@@ -81,8 +83,8 @@ class BrowserURLLoaderThrottle::CheckerOnIO
void CheckUrl(const GURL& url, const std::string& method) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (skip_checks_) {
- base::PostTask(
- FROM_HERE, {content::BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&BrowserURLLoaderThrottle::SkipChecks, throttle_));
return;
}
@@ -108,8 +110,8 @@ class BrowserURLLoaderThrottle::CheckerOnIO
return;
}
- base::PostTask(
- FROM_HERE, {content::BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&BrowserURLLoaderThrottle::NotifySlowCheck, throttle_));
// In this case |proceed| and |showed_interstitial| should be ignored. The
@@ -124,8 +126,8 @@ class BrowserURLLoaderThrottle::CheckerOnIO
void OnCompleteCheck(bool slow_check,
bool proceed,
bool showed_interstitial) {
- base::PostTask(
- FROM_HERE, {content::BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&BrowserURLLoaderThrottle::OnCompleteCheck, throttle_,
slow_check, proceed, showed_interstitial));
}
@@ -139,8 +141,9 @@ class BrowserURLLoaderThrottle::CheckerOnIO
bool skip_checks_ = false;
base::WeakPtr<BrowserURLLoaderThrottle> throttle_;
bool real_time_lookup_enabled_ = false;
- bool enhanced_protection_enabled_ = false;
- base::WeakPtr<RealTimeUrlLookupService> url_lookup_service_;
+ bool can_rt_check_subresource_url_ = false;
+ bool can_check_db_ = true;
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service_;
};
// static
@@ -148,7 +151,7 @@ std::unique_ptr<BrowserURLLoaderThrottle> BrowserURLLoaderThrottle::Create(
GetDelegateCallback delegate_getter,
const base::RepeatingCallback<content::WebContents*()>& web_contents_getter,
int frame_tree_node_id,
- base::WeakPtr<RealTimeUrlLookupService> url_lookup_service) {
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service) {
return base::WrapUnique<BrowserURLLoaderThrottle>(
new BrowserURLLoaderThrottle(std::move(delegate_getter),
web_contents_getter, frame_tree_node_id,
@@ -159,7 +162,7 @@ BrowserURLLoaderThrottle::BrowserURLLoaderThrottle(
GetDelegateCallback delegate_getter,
const base::RepeatingCallback<content::WebContents*()>& web_contents_getter,
int frame_tree_node_id,
- base::WeakPtr<RealTimeUrlLookupService> url_lookup_service) {
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Decide whether to do real time URL lookups or not.
@@ -167,13 +170,18 @@ BrowserURLLoaderThrottle::BrowserURLLoaderThrottle(
url_lookup_service ? url_lookup_service->CanPerformFullURLLookup()
: false;
- bool enhanced_protection_enabled =
- url_lookup_service && url_lookup_service->IsUserEpOptedIn();
+ bool can_rt_check_subresource_url =
+ url_lookup_service && url_lookup_service->CanCheckSubresourceURL();
+ // Decide whether safe browsing database can be checked.
+ // If url_lookup_service is null, safe browsing database should be checked by
+ // default.
+ bool can_check_db =
+ url_lookup_service ? url_lookup_service->CanCheckSafeBrowsingDb() : true;
io_checker_ = std::make_unique<CheckerOnIO>(
std::move(delegate_getter), frame_tree_node_id, web_contents_getter,
weak_factory_.GetWeakPtr(), real_time_lookup_enabled,
- enhanced_protection_enabled, url_lookup_service);
+ can_rt_check_subresource_url, can_check_db, url_lookup_service);
}
BrowserURLLoaderThrottle::~BrowserURLLoaderThrottle() {
@@ -193,8 +201,8 @@ void BrowserURLLoaderThrottle::WillStartRequest(
original_url_ = request->url;
pending_checks_++;
- base::PostTask(
- FROM_HERE, {content::BrowserThread::IO},
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(
&BrowserURLLoaderThrottle::CheckerOnIO::Start,
io_checker_->AsWeakPtr(), request->headers, request->load_flags,
@@ -223,8 +231,8 @@ void BrowserURLLoaderThrottle::WillRedirectRequest(
return;
pending_checks_++;
- base::PostTask(
- FROM_HERE, {content::BrowserThread::IO},
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&BrowserURLLoaderThrottle::CheckerOnIO::CheckUrl,
io_checker_->AsWeakPtr(), redirect_info->new_url,
redirect_info->new_method));
@@ -324,8 +332,8 @@ void BrowserURLLoaderThrottle::NotifySlowCheck() {
}
void BrowserURLLoaderThrottle::DeleteCheckerOnIO() {
- base::DeleteSoon(FROM_HERE, {content::BrowserThread::IO},
- std::move(io_checker_));
+ content::GetIOThreadTaskRunner({})->DeleteSoon(FROM_HERE,
+ std::move(io_checker_));
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.h b/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.h
index d31b38a3dbc..fbd0536a4c7 100644
--- a/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.h
+++ b/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.h
@@ -28,7 +28,7 @@ namespace safe_browsing {
class UrlCheckerDelegate;
-class RealTimeUrlLookupService;
+class RealTimeUrlLookupServiceBase;
// BrowserURLLoaderThrottle is used in the browser process to query
// SafeBrowsing to determine whether a URL and also its redirect URLs are safe
@@ -49,7 +49,7 @@ class BrowserURLLoaderThrottle : public blink::URLLoaderThrottle {
const base::RepeatingCallback<content::WebContents*()>&
web_contents_getter,
int frame_tree_node_id,
- base::WeakPtr<RealTimeUrlLookupService> url_lookup_service);
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service);
~BrowserURLLoaderThrottle() override;
@@ -86,7 +86,7 @@ class BrowserURLLoaderThrottle : public blink::URLLoaderThrottle {
const base::RepeatingCallback<content::WebContents*()>&
web_contents_getter,
int frame_tree_node_id,
- base::WeakPtr<RealTimeUrlLookupService> url_lookup_service);
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service);
// |slow_check| indicates whether it reports the result of a slow check.
// (Please see comments of CheckerOnIO::OnCheckUrlResult() for what slow check
diff --git a/chromium/components/safe_browsing/content/browser/mojo_safe_browsing_impl.cc b/chromium/components/safe_browsing/content/browser/mojo_safe_browsing_impl.cc
index 43e5f816d0b..b9dc2d53324 100644
--- a/chromium/components/safe_browsing/content/browser/mojo_safe_browsing_impl.cc
+++ b/chromium/components/safe_browsing/content/browser/mojo_safe_browsing_impl.cc
@@ -156,7 +156,9 @@ void MojoSafeBrowsingImpl::CreateCheckerAndCheck(
delegate_,
base::BindRepeating(&GetWebContentsFromID, render_process_id_,
static_cast<int>(render_frame_id)),
- /*real_time_lookup_enabled=*/false, /*enhanced_protection_enabled=*/false,
+ /*real_time_lookup_enabled=*/false,
+ /*can_rt_check_subresource_url=*/false,
+ /*can_check_db=*/true,
/*url_lookup_service=*/nullptr);
checker_impl->CheckUrl(
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_url_checker_impl_content.cc b/chromium/components/safe_browsing/content/browser/safe_browsing_url_checker_impl_content.cc
index 4ac3714571e..b22dc6eed7d 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_url_checker_impl_content.cc
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_url_checker_impl_content.cc
@@ -13,7 +13,7 @@
#include "components/safe_browsing/core/common/safebrowsing_constants.h"
#include "components/safe_browsing/core/common/thread_utils.h"
#include "components/safe_browsing/core/realtime/policy_engine.h"
-#include "components/safe_browsing/core/realtime/url_lookup_service.h"
+#include "components/safe_browsing/core/realtime/url_lookup_service_base.h"
#include "components/safe_browsing/core/web_ui/constants.h"
namespace safe_browsing {
@@ -21,8 +21,8 @@ namespace safe_browsing {
bool SafeBrowsingUrlCheckerImpl::CanPerformFullURLLookup(const GURL& url) {
return real_time_lookup_enabled_ &&
RealTimePolicyEngine::CanPerformFullURLLookupForResourceType(
- resource_type_, enhanced_protection_enabled_) &&
- RealTimeUrlLookupService::CanCheckUrl(url);
+ resource_type_, can_rt_check_subresource_url_) &&
+ RealTimeUrlLookupServiceBase::CanCheckUrl(url);
}
void SafeBrowsingUrlCheckerImpl::OnRTLookupRequest(
@@ -48,7 +48,7 @@ void SafeBrowsingUrlCheckerImpl::OnRTLookupResponse(
bool is_expected_resource_type =
(ResourceType::kMainFrame == resource_type_) ||
((ResourceType::kSubFrame == resource_type_) &&
- enhanced_protection_enabled_);
+ can_rt_check_subresource_url_);
DCHECK(is_expected_resource_type);
const GURL& url = urls_[next_index_].url;
@@ -75,8 +75,9 @@ void SafeBrowsingUrlCheckerImpl::OnRTLookupResponse(
// TODO(crbug.com/1033692): Only take the first threat info into account
// because threat infos are returned in decreasing order of severity.
// Consider extend it to support multiple threat types.
- sb_threat_type = RealTimeUrlLookupService::GetSBThreatTypeForRTThreatType(
- response->threat_info(0).threat_type());
+ sb_threat_type =
+ RealTimeUrlLookupServiceBase::GetSBThreatTypeForRTThreatType(
+ response->threat_info(0).threat_type());
}
OnUrlResult(url, sb_threat_type, ThreatMetadata());
}
diff --git a/chromium/components/safe_browsing/content/browser/threat_details.cc b/chromium/components/safe_browsing/content/browser/threat_details.cc
index a71ac3092c4..c63087e8c8f 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details.cc
@@ -20,7 +20,6 @@
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
-#include "base/task/post_task.h"
#include "components/history/core/browser/history_service.h"
#include "components/safe_browsing/content/base_ui_manager.h"
#include "components/safe_browsing/content/browser/threat_details_cache.h"
@@ -849,8 +848,8 @@ void ThreatDetails::OnCacheCollectionReady() {
return;
}
- base::PostTask(
- FROM_HERE, {content::BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&WebUIInfoSingleton::AddToCSBRRsSent,
base::Unretained(WebUIInfoSingleton::GetInstance()),
std::move(report_)));
@@ -877,8 +876,8 @@ void ThreatDetails::MaybeFillReferrerChain() {
void ThreatDetails::AllDone() {
is_all_done_ = true;
- base::PostTask(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(std::move(done_callback_),
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(std::move(done_callback_),
base::Unretained(web_contents())));
}
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_cache.cc b/chromium/components/safe_browsing/content/browser/threat_details_cache.cc
index d0ea614c3bd..70c5ee9278c 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_cache.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details_cache.cc
@@ -12,7 +12,6 @@
#include "base/hash/md5.h"
#include "base/lazy_instance.h"
#include "base/strings/string_util.h"
-#include "base/task/post_task.h"
#include "components/safe_browsing/content/browser/threat_details.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -52,8 +51,8 @@ void ThreatDetailsCacheCollector::StartCacheCollection(
// Post a task in the message loop, so the callers don't need to
// check if we call their callback immediately.
- base::PostTask(FROM_HERE, {BrowserThread::UI},
- base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this));
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this));
}
bool ThreatDetailsCacheCollector::HasStarted() {
@@ -227,15 +226,15 @@ void ThreatDetailsCacheCollector::AdvanceEntry() {
current_load_.reset();
// Create a task so we don't take over the UI thread for too long.
- base::PostTask(FROM_HERE, {BrowserThread::UI},
- base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this));
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this));
}
void ThreatDetailsCacheCollector::AllDone(bool success) {
DVLOG(1) << "AllDone";
DCHECK_CURRENTLY_ON(BrowserThread::UI);
*result_ = success;
- base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(callback_));
+ content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback_));
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_history.cc b/chromium/components/safe_browsing/content/browser/threat_details_history.cc
index d434e97c4ac..c9976122b8c 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_history.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details_history.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/task/post_task.h"
#include "components/safe_browsing/content/browser/threat_details.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -41,8 +40,8 @@ void ThreatDetailsRedirectsCollector::StartHistoryCollection(
return;
}
- base::PostTask(
- FROM_HERE, {BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&ThreatDetailsRedirectsCollector::StartGetRedirects, this,
urls));
}
@@ -107,7 +106,7 @@ void ThreatDetailsRedirectsCollector::OnGotQueryRedirectsTo(
void ThreatDetailsRedirectsCollector::AllDone() {
DVLOG(1) << "AllDone";
- base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(callback_));
+ content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback_));
}
void ThreatDetailsRedirectsCollector::HistoryServiceBeingDeleted(
diff --git a/chromium/components/safe_browsing/content/common/safe_browsing.mojom b/chromium/components/safe_browsing/content/common/safe_browsing.mojom
index a5cc71ad13e..72c21819f36 100644
--- a/chromium/components/safe_browsing/content/common/safe_browsing.mojom
+++ b/chromium/components/safe_browsing/content/common/safe_browsing.mojom
@@ -118,7 +118,13 @@ enum PhishingDetectorResult {
};
[EnableIf=full_safe_browsing]
+// Interface for setting the CSD model and to start phishing classification.
interface PhishingDetector {
+ // A classification model for client-side phishing detection.
+ // The string is an encoded safe_browsing::ClientSideModel protocol buffer, or
+ // empty to disable client-side phishing detection for this renderer.
+ SetPhishingModel(string model);
+
// Tells the renderer to begin phishing detection for the given toplevel URL
// which it has started loading. Returns the serialized request proto and a
// |result| enum to indicate failure. If the URL is phishing the request proto
@@ -126,10 +132,3 @@ interface PhishingDetector {
StartPhishingDetection(url.mojom.Url url)
=> (PhishingDetectorResult result, string request_proto);
};
-
-interface PhishingModelSetter {
- // A classification model for client-side phishing detection.
- // The string is an encoded safe_browsing::ClientSideModel protocol buffer, or
- // empty to disable client-side phishing detection for this renderer.
- SetPhishingModel(string model);
-};
diff --git a/chromium/components/safe_browsing/content/password_protection/BUILD.gn b/chromium/components/safe_browsing/content/password_protection/BUILD.gn
index 26d6f07d5ee..2d06ca399b5 100644
--- a/chromium/components/safe_browsing/content/password_protection/BUILD.gn
+++ b/chromium/components/safe_browsing/content/password_protection/BUILD.gn
@@ -28,6 +28,7 @@ source_set("password_protection") {
"//components/password_manager/core/browser:browser",
"//components/safe_browsing/content/common:interfaces",
"//components/safe_browsing/content/web_ui:web_ui",
+ "//components/safe_browsing/core:client_model_proto",
"//components/safe_browsing/core:csd_proto",
"//components/safe_browsing/core:features",
"//components/safe_browsing/core/browser:referrer_chain_provider",
@@ -43,7 +44,9 @@ source_set("password_protection") {
"//components/url_formatter",
"//content/public/browser:browser",
"//net:net",
+ "//third_party/opencv:emd",
"//third_party/protobuf:protobuf_lite",
+ "//ui/gfx:color_utils",
]
}
if (safe_browsing_mode == 1) {
diff --git a/chromium/components/safe_browsing/content/password_protection/DEPS b/chromium/components/safe_browsing/content/password_protection/DEPS
index c39c8a73429..776629f7b37 100644
--- a/chromium/components/safe_browsing/content/password_protection/DEPS
+++ b/chromium/components/safe_browsing/content/password_protection/DEPS
@@ -10,8 +10,9 @@ include_rules = [
"+net",
"+services/network/public",
"+third_party/blink/public/common/page/page_zoom.h",
- "+ui/gfx/geometry",
+ "+ui/gfx",
"+third_party/skia/include",
+ "+third_party/opencv",
]
specific_include_rules = {
diff --git a/chromium/components/safe_browsing/content/password_protection/metrics_util.cc b/chromium/components/safe_browsing/content/password_protection/metrics_util.cc
index 7b66bf6308b..072a0f97219 100644
--- a/chromium/components/safe_browsing/content/password_protection/metrics_util.cc
+++ b/chromium/components/safe_browsing/content/password_protection/metrics_util.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
#include "base/time/time.h"
#include "net/http/http_status_code.h"
diff --git a/chromium/components/safe_browsing/content/password_protection/mock_password_protection_service.h b/chromium/components/safe_browsing/content/password_protection/mock_password_protection_service.h
index 1e3783718e4..e88bcd4d1d9 100644
--- a/chromium/components/safe_browsing/content/password_protection/mock_password_protection_service.h
+++ b/chromium/components/safe_browsing/content/password_protection/mock_password_protection_service.h
@@ -36,13 +36,13 @@ class MockPasswordProtectionService : public PasswordProtectionService {
MOCK_CONST_METHOD1(GetSignedInNonSyncAccount,
AccountInfo(const std::string&));
MOCK_CONST_METHOD1(IsOtherGaiaAccountGmail, bool(const std::string&));
- MOCK_CONST_METHOD2(IsURLWhitelistedForPasswordEntry,
- bool(const GURL&, RequestOutcome*));
+ MOCK_CONST_METHOD1(IsURLWhitelistedForPasswordEntry, bool(const GURL&));
MOCK_METHOD0(CanSendSamplePing, bool());
MOCK_METHOD0(IsExtendedReporting, bool());
MOCK_METHOD0(IsEnhancedProtection, bool());
MOCK_METHOD0(IsIncognito, bool());
+ MOCK_METHOD1(IsInPasswordAlertMode, bool(ReusedPasswordAccountType));
MOCK_METHOD0(IsHistorySyncEnabled, bool());
MOCK_METHOD0(IsUnderAdvancedProtection, bool());
MOCK_METHOD0(ReportPasswordChanged, void());
@@ -57,10 +57,13 @@ class MockPasswordProtectionService : public PasswordProtectionService {
MOCK_METHOD1(
RemovePhishedSavedPasswordCredential,
void(const std::vector<password_manager::MatchingReusedCredential>&));
- MOCK_METHOD3(IsPingingEnabled,
+ MOCK_METHOD2(IsPingingEnabled,
bool(LoginReputationClientRequest::TriggerType,
- ReusedPasswordAccountType,
- RequestOutcome*));
+ ReusedPasswordAccountType));
+ MOCK_METHOD3(GetPingNotSentReason,
+ RequestOutcome(LoginReputationClientRequest::TriggerType,
+ const GURL&,
+ ReusedPasswordAccountType));
MOCK_METHOD5(ShowModalWarning,
void(content::WebContents*,
RequestOutcome,
@@ -85,8 +88,8 @@ class MockPasswordProtectionService : public PasswordProtectionService {
RequestOutcome,
PasswordType,
const safe_browsing::LoginReputationClientResponse*));
- MOCK_METHOD3(CanShowInterstitial,
- bool(RequestOutcome, ReusedPasswordAccountType, const GURL&));
+ MOCK_METHOD2(CanShowInterstitial,
+ bool(ReusedPasswordAccountType, const GURL&));
MOCK_METHOD5(MaybeStartPasswordFieldOnFocusRequest,
void(content::WebContents*,
const GURL&,
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc
index 82b217141c6..94831c3c64c 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc
@@ -11,7 +11,6 @@
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h"
-#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -159,7 +158,7 @@ void PasswordProtectionRequest::CheckWhitelist() {
auto result_callback =
base::BindOnce(&OnWhitelistCheckDoneOnIO, GetWeakPtr());
tracker_.PostTask(
- base::CreateSingleThreadTaskRunner({BrowserThread::IO}).get(), FROM_HERE,
+ content::GetIOThreadTaskRunner({}).get(), FROM_HERE,
base::BindOnce(&AllowlistCheckerClient::StartCheckCsdWhitelist,
password_protection_service_->database_manager(),
main_frame_url_, std::move(result_callback)));
@@ -170,8 +169,8 @@ void PasswordProtectionRequest::OnWhitelistCheckDoneOnIO(
base::WeakPtr<PasswordProtectionRequest> weak_request,
bool match_whitelist) {
// Don't access weak_request on IO thread. Move it back to UI thread first.
- base::PostTask(
- FROM_HERE, {BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(&PasswordProtectionRequest::OnWhitelistCheckDone,
weak_request, match_whitelist));
}
@@ -332,8 +331,8 @@ void PasswordProtectionRequest::FillRequestProto(bool is_sampled_ping) {
main_frame_url_,
base::BindRepeating(&PasswordProtectionRequest::OnGetDomFeatures,
GetWeakPtr()));
- base::PostDelayedTask(
- FROM_HERE, {BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostDelayedTask(
+ FROM_HERE,
base::BindOnce(&PasswordProtectionRequest::OnGetDomFeatureTimeout,
GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kDomFeatureTimeoutMs));
@@ -520,8 +519,8 @@ void PasswordProtectionRequest::StartTimeout() {
// The weak pointer used for the timeout will be invalidated (and
// hence would prevent the timeout) if the check completes on time and
// execution reaches Finish().
- base::PostDelayedTask(
- FROM_HERE, {BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostDelayedTask(
+ FROM_HERE,
base::BindOnce(&PasswordProtectionRequest::Cancel, GetWeakPtr(), true),
base::TimeDelta::FromMilliseconds(request_timeout_in_ms_));
}
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc
index f93318f850b..6a180cb90ef 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc
@@ -17,7 +17,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
-#include "base/task/post_task.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
@@ -101,18 +100,22 @@ void PasswordProtectionService::MaybeStartPasswordFieldOnFocusRequest(
const GURL& password_form_frame_url,
const std::string& hosted_domain) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RequestOutcome reason;
- if (CanSendPing(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
- main_frame_url,
- GetPasswordProtectionReusedPasswordAccountType(
- PasswordType::PASSWORD_TYPE_UNKNOWN,
- /*username=*/""),
- &reason)) {
+ LoginReputationClientRequest::TriggerType trigger_type =
+ LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE;
+ ReusedPasswordAccountType reused_password_account_type =
+ GetPasswordProtectionReusedPasswordAccountType(
+ PasswordType::PASSWORD_TYPE_UNKNOWN,
+ /*username=*/"");
+ if (CanSendPing(trigger_type, main_frame_url, reused_password_account_type)) {
StartRequest(web_contents, main_frame_url, password_form_action,
password_form_frame_url, /* username */ "",
PasswordType::PASSWORD_TYPE_UNKNOWN,
{}, /* matching_reused_credentials: not used for this type */
LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
+ } else {
+ RequestOutcome reason = GetPingNotSentReason(trigger_type, main_frame_url,
+ reused_password_account_type);
+ LogNoPingingReason(trigger_type, reason, reused_password_account_type);
}
}
#endif
@@ -127,13 +130,10 @@ void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
matching_reused_credentials,
bool password_field_exists) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ LoginReputationClientRequest::TriggerType trigger_type =
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT;
ReusedPasswordAccountType reused_password_account_type =
GetPasswordProtectionReusedPasswordAccountType(password_type, username);
- RequestOutcome reason;
- // Need to populate |reason| to be passed into CanShowInterstitial.
- bool can_send_ping =
- CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- main_frame_url, reused_password_account_type, &reason);
if (IsSupportedPasswordTypeForPinging(password_type)) {
#if BUILDFLAG(FULL_SAFE_BROWSING)
// Collect metrics about typical page-zoom on login pages.
@@ -143,7 +143,8 @@ void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
"PasswordProtection.PageZoomFactor",
static_cast<int>(100 * blink::PageZoomLevelToZoomFactor(zoom_level)));
#endif // defined(FULL_SAFE_BROWSING)
- if (can_send_ping) {
+ if (CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ main_frame_url, reused_password_account_type)) {
saved_passwords_matching_reused_credentials_ =
matching_reused_credentials;
StartRequest(web_contents, main_frame_url, GURL(), GURL(), username,
@@ -151,6 +152,9 @@ void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
password_field_exists);
} else {
+ RequestOutcome reason = GetPingNotSentReason(
+ trigger_type, main_frame_url, reused_password_account_type);
+ LogNoPingingReason(trigger_type, reason, reused_password_account_type);
#if defined(SYNC_PASSWORD_REUSE_WARNING_ENABLED)
if (reused_password_account_type.is_account_syncing())
MaybeLogPasswordReuseLookupEvent(web_contents, reason, password_type,
@@ -160,8 +164,9 @@ void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
}
#if defined(SYNC_PASSWORD_REUSE_WARNING_ENABLED)
- if (CanShowInterstitial(reason, reused_password_account_type,
- main_frame_url)) {
+ if (CanShowInterstitial(reused_password_account_type, main_frame_url)) {
+ LogPasswordAlertModeOutcome(RequestOutcome::SUCCEEDED,
+ reused_password_account_type);
username_for_last_shown_warning_ = username;
reused_password_account_type_for_last_shown_warning_ =
reused_password_account_type;
@@ -247,24 +252,9 @@ void PasswordProtectionService::StartRequest(
bool PasswordProtectionService::CanSendPing(
LoginReputationClientRequest::TriggerType trigger_type,
const GURL& main_frame_url,
- ReusedPasswordAccountType password_type,
- RequestOutcome* reason) {
- *reason = RequestOutcome::UNKNOWN;
- bool is_pinging_enabled =
- IsPingingEnabled(trigger_type, password_type, reason);
- // Pinging is enabled for password_reuse trigger level; however we need to
- // make sure *reason is set appropriately.
- PasswordProtectionTrigger trigger_level =
- GetPasswordProtectionWarningTriggerPref(password_type);
- if (trigger_level == PASSWORD_REUSE) {
- *reason = RequestOutcome::PASSWORD_ALERT_MODE;
- }
- if (is_pinging_enabled &&
- !IsURLWhitelistedForPasswordEntry(main_frame_url, reason)) {
- return true;
- }
- LogNoPingingReason(trigger_type, *reason, password_type);
- return false;
+ ReusedPasswordAccountType password_type) {
+ return IsPingingEnabled(trigger_type, password_type) &&
+ !IsURLWhitelistedForPasswordEntry(main_frame_url);
}
void PasswordProtectionService::RequestFinished(
@@ -408,8 +398,8 @@ void PasswordProtectionService::FillUserPopulation(
void PasswordProtectionService::OnURLsDeleted(
history::HistoryService* history_service,
const history::DeletionInfo& deletion_info) {
- base::PostTask(
- FROM_HERE, {BrowserThread::UI},
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindRepeating(&PasswordProtectionService::
RemoveUnhandledSyncPasswordReuseOnURLsDeleted,
GetWeakPtr(), deletion_info.IsAllHistory(),
@@ -551,7 +541,8 @@ bool PasswordProtectionService::IsSupportedPasswordTypeForPinging(
PasswordType password_type) const {
switch (password_type) {
case PasswordType::SAVED_PASSWORD:
- return true;
+ return base::FeatureList::IsEnabled(
+ safe_browsing::kPasswordProtectionForSavedPasswords);
case PasswordType::PRIMARY_ACCOUNT_PASSWORD:
return true;
case PasswordType::ENTERPRISE_PASSWORD:
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_service.h b/chromium/components/safe_browsing/content/password_protection/password_protection_service.h
index 307e95dbd3d..1823146c4b4 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_service.h
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_service.h
@@ -208,9 +208,7 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// If |url| matches Safe Browsing whitelist domains, password protection
// change password URL, or password protection login URLs in the enterprise
// policy.
- virtual bool IsURLWhitelistedForPasswordEntry(
- const GURL& url,
- RequestOutcome* reason) const = 0;
+ virtual bool IsURLWhitelistedForPasswordEntry(const GURL& url) const = 0;
// Persist the phished saved password credential in the "compromised
// credentials" table. Calls the password store to add a row for each
@@ -300,14 +298,12 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
friend class PasswordProtectionRequest;
// Chrome can send password protection ping if it is allowed by for the
- // |trigger_type| and if Safe Browsing can compute reputation of
- // |main_frame_url| (e.g. Safe Browsing is not able to compute reputation of a
- // private IP or a local host). Update |reason| if sending ping is not
- // allowed. |password_type| is used for UMA metric recording.
+ // |trigger_type| and |password_type| and if Safe Browsing can compute
+ // reputation of |main_frame_url| (e.g. Safe Browsing is not able to compute
+ // reputation of a private IP or a local host).
bool CanSendPing(LoginReputationClientRequest::TriggerType trigger_type,
const GURL& main_frame_url,
- ReusedPasswordAccountType password_type,
- RequestOutcome* reason);
+ ReusedPasswordAccountType password_type);
// Called by a PasswordProtectionRequest instance when it finishes to remove
// itself from |requests_|.
@@ -364,10 +360,12 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
virtual bool IsIncognito() = 0;
+ virtual bool IsInPasswordAlertMode(
+ ReusedPasswordAccountType password_type) = 0;
+
virtual bool IsPingingEnabled(
LoginReputationClientRequest::TriggerType trigger_type,
- ReusedPasswordAccountType password_type,
- RequestOutcome* reason) = 0;
+ ReusedPasswordAccountType password_type) = 0;
virtual bool IsHistorySyncEnabled() = 0;
@@ -408,10 +406,8 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
bool IsModalWarningShowingInWebContents(content::WebContents* web_contents);
// Determines if we should show chrome://reset-password interstitial based on
- // previous request outcome, the reused |password_type| and the
- // |main_frame_url|.
- virtual bool CanShowInterstitial(RequestOutcome reason,
- ReusedPasswordAccountType password_type,
+ // the reused |password_type| and the |main_frame_url|.
+ virtual bool CanShowInterstitial(ReusedPasswordAccountType password_type,
const GURL& main_frame_url) = 0;
#endif
@@ -422,6 +418,13 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
virtual LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType
GetSyncAccountType() const = 0;
+ // Returns the reason why a ping is not sent based on the |trigger_type|,
+ // |url| and |password_type|. Crash if |CanSendPing| is true.
+ virtual RequestOutcome GetPingNotSentReason(
+ LoginReputationClientRequest::TriggerType trigger_type,
+ const GURL& url,
+ ReusedPasswordAccountType password_type) = 0;
+
const std::list<std::string>& common_spoofed_domains() const {
return common_spoofed_domains_;
}
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
index d7c00d3fe41..26357224b45 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
@@ -96,6 +96,8 @@ class TestPhishingDetector : public mojom::PhishingDetector {
mojo::PendingReceiver<mojom::PhishingDetector>(std::move(handle)));
}
+ void SetPhishingModel(const std::string& model) override {}
+
void StartPhishingDetection(
const GURL& url,
StartPhishingDetectionCallback callback) override {
@@ -275,7 +277,7 @@ class PasswordProtectionServiceTest : public ::testing::TestWithParam<bool> {
EXPECT_CALL(*password_protection_service_, IsIncognito())
.WillRepeatedly(Return(false));
EXPECT_CALL(*password_protection_service_,
- IsURLWhitelistedForPasswordEntry(_, _))
+ IsURLWhitelistedForPasswordEntry(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(*password_protection_service_,
GetPasswordProtectionWarningTriggerPref(_))
@@ -1166,9 +1168,13 @@ TEST_P(PasswordProtectionServiceTest, VerifyShouldShowModalWarning) {
reused_password_account_type.set_account_type(
ReusedPasswordAccountType::SAVED_PASSWORD);
- EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
+ EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- reused_password_account_type, LoginReputationClientResponse::PHISHING));
+ reused_password_account_type,
+ LoginReputationClientResponse::LOW_REPUTATION));
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ safe_browsing::kPasswordProtectionForSavedPasswords);
EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
reused_password_account_type,
@@ -1330,38 +1336,26 @@ TEST_P(PasswordProtectionServiceTest, VerifyIsSupportedPasswordTypeForPinging) {
.WillRepeatedly(Return(account_info));
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
- PasswordType::SAVED_PASSWORD));
- EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
PasswordType::PRIMARY_ACCOUNT_PASSWORD));
-// kPasswordProtectionForSignedInUsers is disabled by default on Android.
-#if defined(OS_ANDROID)
EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-#else
- EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-#endif
PasswordType::OTHER_GAIA_PASSWORD));
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
PasswordType::ENTERPRISE_PASSWORD));
-
- EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+ EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
PasswordType::SAVED_PASSWORD));
- EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
- PasswordType::ENTERPRISE_PASSWORD));
{
base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
+ feature_list.InitAndEnableFeature(
safe_browsing::kPasswordProtectionForSignedInUsers);
- // Only ping for signed in, non-syncing users if the experiment is on.
- EXPECT_FALSE(
- password_protection_service_->IsSupportedPasswordTypeForPinging(
- PasswordType::OTHER_GAIA_PASSWORD));
+ EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+ PasswordType::OTHER_GAIA_PASSWORD));
}
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
- safe_browsing::kPasswordProtectionForSignedInUsers);
+ safe_browsing::kPasswordProtectionForSavedPasswords);
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
- PasswordType::OTHER_GAIA_PASSWORD));
+ PasswordType::SAVED_PASSWORD));
}
}
diff --git a/chromium/components/safe_browsing/content/password_protection/visual_utils.cc b/chromium/components/safe_browsing/content/password_protection/visual_utils.cc
index 85349795389..c751167b8a3 100644
--- a/chromium/components/safe_browsing/content/password_protection/visual_utils.cc
+++ b/chromium/components/safe_browsing/content/password_protection/visual_utils.cc
@@ -7,9 +7,14 @@
#include "components/safe_browsing/content/password_protection/visual_utils.h"
+#include "base/check_op.h"
#include "base/numerics/checked_math.h"
+#include "components/safe_browsing/core/proto/client_model.pb.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+#include "third_party/opencv/src/emd_wrapper.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixmap.h"
+#include "ui/gfx/color_utils.h"
namespace safe_browsing {
namespace visual_utils {
@@ -22,6 +27,87 @@ const int kPHashDownsampleWidth = 288;
const int kPHashDownsampleHeight = 288;
const int kPHashBlockSize = 6;
+// Constants for computing Earth Movers Distance (EMD) between ColorHistograms.
+const float kMaxCentroidDistance = 1.414;
+const float kMaxColorDistance = 14;
+
+size_t GetBitCount(uint8_t byte) {
+ size_t count = 0;
+ for (; byte > 0; byte >>= 1) {
+ if (byte & 1)
+ count++;
+ }
+
+ return count;
+}
+
+bool GetHashDistance(const std::string& hash1,
+ const std::string& hash2,
+ size_t* out) {
+ // The beginning of the hash is a Varint representing the stride. For values
+ // at most 127, this is just the value of the first char. Chrome only
+ // generates strides less than 128, so we can simply extract the first char.
+ if (hash1[0] != hash2[0])
+ return false;
+ if (hash1[0] & 0x80)
+ return false;
+
+ size_t count = std::min(hash1.size(), hash2.size());
+ size_t distance = 8 * (std::max(hash1.size(), hash2.size()) - count);
+ for (size_t i = 1; i < count; i++) {
+ distance += GetBitCount(hash1[i] ^ hash2[i]);
+ }
+
+ *out = distance;
+ return true;
+}
+
+opencv::PointDistribution HistogramBinsToPointDistribution(
+ const google::protobuf::RepeatedPtrField<VisualFeatures::ColorHistogramBin>&
+ bins) {
+ opencv::PointDistribution distribution;
+ distribution.dimensions = 5;
+ for (const VisualFeatures::ColorHistogramBin& bin : bins) {
+ distribution.weights.push_back(bin.weight());
+ std::vector<float> position(5);
+ position[0] = bin.centroid_x() / kMaxCentroidDistance;
+ position[1] = bin.centroid_y() / kMaxCentroidDistance;
+ position[2] = bin.quantized_r() / kMaxColorDistance;
+ position[3] = bin.quantized_g() / kMaxColorDistance;
+ position[4] = bin.quantized_b() / kMaxColorDistance;
+ distribution.positions.push_back(std::move(position));
+ }
+
+ return distribution;
+}
+
+bool ImageHasColorInRange(const SkBitmap& image,
+ const MatchRule::ColorRange& color_range) {
+ for (int i = 0; i < image.width(); i++) {
+ for (int j = 0; j < image.height(); j++) {
+ SkScalar hsv[3];
+ SkColorToHSV(image.getColor(i, j), hsv);
+ if (color_range.low() <= hsv[0] && hsv[0] <= color_range.high())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint8_t GetMedian(const std::vector<uint8_t>& data) {
+ std::vector<uint8_t> buffer;
+ buffer.assign(data.begin(), data.end());
+ std::vector<uint8_t>::iterator middle = buffer.begin() + (buffer.size() / 2);
+ std::nth_element(buffer.begin(), middle, buffer.end());
+ if (buffer.size() % 2 == 1) {
+ return *middle;
+ } else {
+ // For even-sized sets, return the average of the two middle elements.
+ return (*middle + *std::max_element(buffer.begin(), middle)) / 2;
+ }
+}
+
} // namespace
// A QuantizedColor takes the highest 3 bits of R, G, and B, and concatenates
@@ -171,5 +257,101 @@ std::unique_ptr<SkBitmap> BlockMeanAverage(const SkBitmap& image,
return target;
}
+std::string GetHashFromBlurredImage(
+ VisualFeatures::BlurredImage blurred_image) {
+ DCHECK_EQ(blurred_image.data().size(),
+ 3u * blurred_image.width() * blurred_image.height());
+ // Convert the blurred image to grayscale.
+ std::vector<uint8_t> luma_values;
+ luma_values.resize(blurred_image.width() * blurred_image.height());
+ for (size_t i = 0; i < luma_values.size(); i++) {
+ luma_values[i] = color_utils::GetLuma(SkColorSetRGB(
+ static_cast<unsigned char>(blurred_image.data()[3 * i]),
+ static_cast<unsigned char>(blurred_image.data()[3 * i + 1]),
+ static_cast<unsigned char>(blurred_image.data()[3 * i + 2])));
+ }
+
+ uint8_t median_luma = GetMedian(luma_values);
+
+ std::string output;
+
+ // The server-side hash generation writes a Varint here, rather than just an
+ // int. These encodings coincide as long as the width is at most 127. If
+ // we begin using larger widths, we need to implement the Varint encoding used
+ // on the server.
+ DCHECK_LT(blurred_image.width(), 128);
+ output.push_back(static_cast<unsigned char>(blurred_image.width()));
+
+ // Write the output bitstring.
+ unsigned char next_byte = 0;
+ int bits_encoded_so_far = 0;
+ for (const uint8_t luma_value : luma_values) {
+ next_byte <<= 1;
+ if (luma_value >= median_luma)
+ next_byte |= 1;
+
+ ++bits_encoded_so_far;
+ if (bits_encoded_so_far == 8) {
+ output.push_back(next_byte);
+ bits_encoded_so_far = 0;
+ }
+ }
+
+ if (bits_encoded_so_far != 0) {
+ next_byte <<= 8 - bits_encoded_so_far;
+ output.push_back(next_byte);
+ }
+
+ return output;
+}
+
+base::Optional<VisionMatchResult> IsVisualMatch(const SkBitmap& image,
+ const VisualTarget& target) {
+ VisualFeatures::BlurredImage blurred_image;
+ if (!GetBlurredImage(image, &blurred_image))
+ return base::nullopt;
+ std::string hash = GetHashFromBlurredImage(blurred_image);
+ size_t hash_distance;
+ bool has_hash_distance = GetHashDistance(hash, target.hash(), &hash_distance);
+
+ VisualFeatures::ColorHistogram histogram;
+ if (!GetHistogramForImage(image, &histogram))
+ return base::nullopt;
+
+ opencv::PointDistribution point_distribution =
+ HistogramBinsToPointDistribution(histogram.bins());
+ base::Optional<double> color_distance = opencv::EMD(
+ point_distribution, HistogramBinsToPointDistribution(target.bins()));
+
+ for (const MatchRule& match_rule : target.match_config().match_rule()) {
+ bool is_match = true;
+ if (match_rule.has_hash_distance()) {
+ is_match &=
+ (has_hash_distance && hash_distance <= match_rule.hash_distance());
+ }
+
+ if (match_rule.has_color_distance()) {
+ is_match &= (color_distance.has_value() &&
+ color_distance.value() <= match_rule.color_distance());
+ }
+
+ for (const MatchRule::ColorRange& color_range : match_rule.color_range()) {
+ is_match &= ImageHasColorInRange(image, color_range);
+ }
+
+ if (is_match) {
+ VisionMatchResult result;
+ result.set_matched_target_digest(target.digest());
+ if (has_hash_distance)
+ result.set_vision_matched_phash_score(hash_distance);
+ if (color_distance.has_value())
+ result.set_vision_matched_emd_score(color_distance.value());
+ return result;
+ }
+ }
+
+ return base::nullopt;
+}
+
} // namespace visual_utils
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/password_protection/visual_utils.h b/chromium/components/safe_browsing/content/password_protection/visual_utils.h
index 6d2d24fdf40..34b6764efa5 100644
--- a/chromium/components/safe_browsing/content/password_protection/visual_utils.h
+++ b/chromium/components/safe_browsing/content/password_protection/visual_utils.h
@@ -7,6 +7,8 @@
#include <string>
+#include "base/optional.h"
+#include "components/safe_browsing/core/proto/client_model.pb.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -39,6 +41,14 @@ bool GetBlurredImage(const SkBitmap& image,
std::unique_ptr<SkBitmap> BlockMeanAverage(const SkBitmap& image,
int block_size);
+// Returns the hash used to compare blurred images.
+std::string GetHashFromBlurredImage(VisualFeatures::BlurredImage blurred_image);
+
+// Returns whether the given |image| is a match for the |target|. Returns
+// nullopt in the case of no match, and the VisionMatchResult if it is a match.
+base::Optional<VisionMatchResult> IsVisualMatch(const SkBitmap& image,
+ const VisualTarget& target);
+
} // namespace visual_utils
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc b/chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc
index 140c97884d2..752e65dbe3e 100644
--- a/chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc
+++ b/chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc
@@ -252,5 +252,264 @@ TEST_F(VisualUtilsTest, BlockMeanAveragePartialBlocks) {
EXPECT_EQ(*blocks->getAddr32(1, 1), kBlue);
}
+TEST_F(VisualUtilsTest, IsVisualMatchHash) {
+ {
+ // An all-white image should hash to all 1-bits.
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+
+ std::vector<unsigned char> target_hash;
+ target_hash.push_back('\x30');
+ for (int i = 0; i < 288; i++)
+ target_hash.push_back('\xff');
+
+ VisualTarget target;
+ target.set_hash(target_hash.data(), target_hash.size());
+ target.mutable_match_config()->add_match_rule()->set_hash_distance(0.0);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+ }
+
+ {
+ // Make the top quarter black, and the corresponding bits of the hash should
+ // be 0.
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 250; y++)
+ *bitmap_.getAddr32(x, y) = kBlack;
+
+ std::vector<unsigned char> target_hash;
+ target_hash.push_back('\x30');
+ for (int i = 0; i < 72; i++)
+ target_hash.push_back('\x00');
+ for (int i = 0; i < 216; i++)
+ target_hash.push_back('\xff');
+ VisualTarget target;
+ target.set_hash(target_hash.data(), target_hash.size());
+
+ target.mutable_match_config()->add_match_rule()->set_hash_distance(0.0);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+ }
+}
+
+TEST_F(VisualUtilsTest, IsVisualMatchHashPartialMatch) {
+ // Make the top quarter black, and the corresponding bits of the hash should
+ // be 0.
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 250; y++)
+ *bitmap_.getAddr32(x, y) = kBlack;
+ for (int x = 0; x < 1000; x++)
+ for (int y = 250; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+
+ std::vector<unsigned char> target_hash;
+ target_hash.push_back('\x30');
+ for (int i = 0; i < 75; i++)
+ target_hash.push_back('\x00');
+ for (int i = 0; i < 213; i++)
+ target_hash.push_back('\xff');
+
+ VisualTarget target;
+ target.set_hash(target_hash.data(), target_hash.size());
+ target.mutable_match_config()->add_match_rule()->set_hash_distance(23.0);
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+ target.mutable_match_config()->add_match_rule()->set_hash_distance(24.0);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+}
+
+TEST_F(VisualUtilsTest, IsVisualMatchHashStrideComparison) {
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+
+ std::vector<unsigned char> target_hash;
+ target_hash.push_back('\x30');
+ for (int i = 0; i < 288; i++)
+ target_hash.push_back('\xff');
+
+ VisualTarget target;
+ target.set_hash(target_hash.data(), target_hash.size());
+ target.mutable_match_config()->add_match_rule()->set_hash_distance(0.0);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ target_hash[0] = '\x00';
+ target.set_hash(target_hash.data(), target_hash.size());
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+}
+
+TEST_F(VisualUtilsTest, IsVisualMatchHistogramOnly) {
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+
+ {
+ VisualTarget target;
+ VisualFeatures::ColorHistogramBin* bin = target.add_bins();
+ // Our coordinates range from 0 to 999, giving an average of 0.4995 instead
+ // of 0.5.
+ bin->set_centroid_x(0.4995);
+ bin->set_centroid_y(0.4995);
+ bin->set_quantized_r(7);
+ bin->set_quantized_g(7);
+ bin->set_quantized_b(7);
+ bin->set_weight(1.0);
+ target.mutable_match_config()->add_match_rule()->set_color_distance(0.0);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+ }
+
+ {
+ // Move the target histogram to have centroid 0,0. This leads to a distance
+ // just under 0.5 between the actual and target histograms.
+ VisualTarget target;
+ VisualFeatures::ColorHistogramBin* bin = target.add_bins();
+ bin->set_centroid_x(0);
+ bin->set_centroid_y(0);
+ bin->set_quantized_r(7);
+ bin->set_quantized_g(7);
+ bin->set_quantized_b(7);
+ bin->set_weight(1.0);
+
+ MatchRule* match_rule = target.mutable_match_config()->add_match_rule();
+ match_rule->set_color_distance(0.5);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ match_rule->set_color_distance(0.4);
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+ }
+
+ {
+ // Change the target histogram color slightly. This leads to a distance
+ // of roughly 0.12 between the actual and target histogram.
+ VisualTarget target;
+ VisualFeatures::ColorHistogramBin* bin = target.add_bins();
+ bin->set_centroid_x(0.4995);
+ bin->set_centroid_y(0.4995);
+ bin->set_quantized_r(6);
+ bin->set_quantized_g(6);
+ bin->set_quantized_b(6);
+ bin->set_weight(1.0);
+
+ MatchRule* match_rule = target.mutable_match_config()->add_match_rule();
+ match_rule->set_color_distance(0.2);
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ match_rule->set_color_distance(0.1);
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+ }
+}
+
+TEST_F(VisualUtilsTest, IsVisualMatchColorRange) {
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+ *bitmap_.getAddr32(0, 0) = kBlue;
+
+ SkScalar hsv[3];
+ SkColorToHSV(bitmap_.getColor(0, 0), hsv);
+ SkScalar target_hue = hsv[0];
+ VisualTarget target;
+ MatchRule::ColorRange* color_range =
+ target.mutable_match_config()->add_match_rule()->add_color_range();
+ color_range->set_low(target_hue);
+ color_range->set_high(target_hue);
+
+ // Blue hue present
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ // Color range too high
+ color_range->set_low(target_hue + 1);
+ color_range->set_high(target_hue + 1);
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+
+ // Color range too low
+ color_range->set_low(target_hue - 1);
+ color_range->set_high(target_hue - 1);
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+
+ // No blue hue present
+ *bitmap_.getAddr32(0, 0) = kWhite;
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+}
+
+TEST_F(VisualUtilsTest, IsVisualMatchMultipleColorRanges) {
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+ *bitmap_.getAddr32(0, 0) = kBlue;
+ *bitmap_.getAddr32(1, 0) = kGreen;
+
+ SkScalar hsv[3];
+ SkColorToHSV(bitmap_.getColor(0, 0), hsv);
+ SkScalar blue_hue = hsv[0];
+ VisualTarget target;
+ MatchRule* match_rule = target.mutable_match_config()->add_match_rule();
+ MatchRule::ColorRange* color_range = match_rule->add_color_range();
+ color_range->set_low(blue_hue);
+ color_range->set_high(blue_hue);
+
+ SkColorToHSV(bitmap_.getColor(1, 0), hsv);
+ SkScalar green_hue = hsv[0];
+ color_range = match_rule->add_color_range();
+ color_range->set_low(green_hue);
+ color_range->set_high(green_hue);
+
+ // Both hues present
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ // No blue hue present
+ *bitmap_.getAddr32(0, 0) = kWhite;
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+
+ // No green hue present
+ *bitmap_.getAddr32(0, 0) = kBlue;
+ *bitmap_.getAddr32(1, 0) = kWhite;
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+
+ // Neither hue present
+ *bitmap_.getAddr32(0, 0) = kWhite;
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+}
+
+TEST_F(VisualUtilsTest, IsVisualMatchMultipleMatchRules) {
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = kWhite;
+ *bitmap_.getAddr32(0, 0) = kBlue;
+ *bitmap_.getAddr32(1, 0) = kGreen;
+
+ // Create a target with two match rules, one matching blue pixels and one
+ // matching green.
+ VisualTarget target;
+ MatchRule* match_rule_blue = target.mutable_match_config()->add_match_rule();
+ MatchRule::ColorRange* color_range = match_rule_blue->add_color_range();
+ SkScalar hsv[3];
+ SkColorToHSV(bitmap_.getColor(0, 0), hsv);
+ SkScalar blue_hue = hsv[0];
+ color_range->set_low(blue_hue);
+ color_range->set_high(blue_hue);
+
+ MatchRule* match_rule_green = target.mutable_match_config()->add_match_rule();
+ color_range = match_rule_green->add_color_range();
+ SkColorToHSV(bitmap_.getColor(1, 0), hsv);
+ SkScalar green_hue = hsv[0];
+ color_range->set_low(green_hue);
+ color_range->set_high(green_hue);
+
+ // Both hues present
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ // No blue hue present
+ *bitmap_.getAddr32(0, 0) = kWhite;
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ // No green hue present
+ *bitmap_.getAddr32(0, 0) = kBlue;
+ *bitmap_.getAddr32(1, 0) = kWhite;
+ EXPECT_TRUE(IsVisualMatch(bitmap_, target).has_value());
+
+ // Neither hue present
+ *bitmap_.getAddr32(0, 0) = kWhite;
+ EXPECT_FALSE(IsVisualMatch(bitmap_, target).has_value());
+}
+
} // namespace visual_utils
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc b/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc
index 4b92b8fcffa..d9fef3975a1 100644
--- a/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc
+++ b/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc
@@ -23,22 +23,9 @@ namespace safe_browsing {
WebSocketSBHandshakeThrottle::WebSocketSBHandshakeThrottle(
mojom::SafeBrowsing* safe_browsing,
int render_frame_id)
- : render_frame_id_(render_frame_id),
- safe_browsing_(safe_browsing),
- result_(Result::UNKNOWN) {}
+ : render_frame_id_(render_frame_id), safe_browsing_(safe_browsing) {}
-WebSocketSBHandshakeThrottle::~WebSocketSBHandshakeThrottle() {
- // ThrottleHandshake() should always be called, but since that is done all the
- // way over in Blink, just avoid logging if it is not called rather than
- // DCHECK()ing.
- if (start_time_.is_null())
- return;
- if (result_ == Result::UNKNOWN) {
- result_ = Result::ABANDONED;
- UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Abandoned",
- base::TimeTicks::Now() - start_time_);
- }
-}
+WebSocketSBHandshakeThrottle::~WebSocketSBHandshakeThrottle() = default;
void WebSocketSBHandshakeThrottle::ThrottleHandshake(
const blink::WebURL& url,
@@ -48,7 +35,8 @@ void WebSocketSBHandshakeThrottle::ThrottleHandshake(
completion_callback_ = std::move(completion_callback);
url_ = url;
int load_flags = 0;
- start_time_ = base::TimeTicks::Now();
+ DCHECK_EQ(state_, State::kInitial);
+ state_ = State::kStarted;
safe_browsing_->CreateCheckerAndCheck(
render_frame_id_, url_checker_.BindNewPipeAndPassReceiver(), url, "GET",
net::HttpRequestHeaders(), load_flags,
@@ -65,17 +53,14 @@ void WebSocketSBHandshakeThrottle::ThrottleHandshake(
void WebSocketSBHandshakeThrottle::OnCompleteCheck(bool proceed,
bool showed_interstitial) {
- DCHECK(!start_time_.is_null());
- base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
+ DCHECK_EQ(state_, State::kStarted);
if (proceed) {
- result_ = Result::SAFE;
- UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Safe", elapsed);
+ state_ = State::kSafe;
std::move(completion_callback_).Run(base::nullopt);
} else {
// When the insterstitial is dismissed the page is navigated and this object
// is destroyed before reaching here.
- result_ = Result::BLOCKED;
- UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Blocked", elapsed);
+ state_ = State::kBlocked;
std::move(completion_callback_)
.Run(blink::WebString::FromUTF8(base::StringPrintf(
"WebSocket connection to %s failed safe browsing check",
@@ -93,7 +78,8 @@ void WebSocketSBHandshakeThrottle::OnCheckResult(
return;
}
- // TODO(yzshen): Notify the network service to pause processing response body.
+ // TODO(yzshen): Notify the network service to stop reading from the
+ // WebSocket.
if (!notifier_receiver_) {
notifier_receiver_ =
std::make_unique<mojo::Receiver<mojom::UrlCheckNotifier>>(this);
@@ -102,14 +88,12 @@ void WebSocketSBHandshakeThrottle::OnCheckResult(
}
void WebSocketSBHandshakeThrottle::OnMojoDisconnect() {
- DCHECK_EQ(result_, Result::UNKNOWN);
+ DCHECK(state_ == State::kStarted);
url_checker_.reset();
notifier_receiver_.reset();
- // Make the destructor record NOT_SUPPORTED in the result histogram.
- result_ = Result::NOT_SUPPORTED;
- // Don't record the time elapsed because it's unlikely to be meaningful.
+ state_ = State::kNotSupported;
std::move(completion_callback_).Run(base::nullopt);
// |this| is destroyed here.
}
diff --git a/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.h b/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.h
index 53f7761c78b..c703942d2e0 100644
--- a/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.h
+++ b/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.h
@@ -35,14 +35,12 @@ class WebSocketSBHandshakeThrottle : public blink::WebSocketHandshakeThrottle,
completion_callback) override;
private:
- // These values are logged to UMA so do not renumber or reuse.
- enum class Result {
- UNKNOWN = 0,
- SAFE = 1,
- BLOCKED = 2,
- ABANDONED = 3,
- NOT_SUPPORTED = 4,
- RESULT_COUNT
+ enum class State {
+ kInitial,
+ kStarted,
+ kSafe,
+ kBlocked,
+ kNotSupported,
};
// mojom::UrlCheckNotifier implementation.
@@ -60,8 +58,10 @@ class WebSocketSBHandshakeThrottle : public blink::WebSocketHandshakeThrottle,
mojo::Remote<mojom::SafeBrowsingUrlChecker> url_checker_;
mojom::SafeBrowsing* safe_browsing_;
std::unique_ptr<mojo::Receiver<mojom::UrlCheckNotifier>> notifier_receiver_;
- base::TimeTicks start_time_;
- Result result_;
+
+ // |state_| is used to validate that events happen in the right order. It
+ // isn't used to control the behaviour of the class.
+ State state_ = State::kInitial;
base::WeakPtrFactory<WebSocketSBHandshakeThrottle> weak_factory_{this};
diff --git a/chromium/components/safe_browsing/content/triggers/ad_popup_trigger.cc b/chromium/components/safe_browsing/content/triggers/ad_popup_trigger.cc
index ce197ab32b7..3206c87eb4e 100644
--- a/chromium/components/safe_browsing/content/triggers/ad_popup_trigger.cc
+++ b/chromium/components/safe_browsing/content/triggers/ad_popup_trigger.cc
@@ -14,7 +14,6 @@
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
#include "components/safe_browsing/content/triggers/trigger_util.h"
#include "components/safe_browsing/core/features.h"
#include "components/safe_browsing/core/triggers/trigger_manager.h"
@@ -68,8 +67,7 @@ AdPopupTrigger::AdPopupTrigger(
prefs_(prefs),
url_loader_factory_(url_loader_factory),
history_service_(history_service),
- task_runner_(
- base::CreateSingleThreadTaskRunner({content::BrowserThread::UI})) {}
+ task_runner_(content::GetUIThreadTaskRunner({})) {}
AdPopupTrigger::~AdPopupTrigger() {}
diff --git a/chromium/components/safe_browsing/content/triggers/ad_redirect_trigger.cc b/chromium/components/safe_browsing/content/triggers/ad_redirect_trigger.cc
index a281138194a..842274ef16f 100644
--- a/chromium/components/safe_browsing/content/triggers/ad_redirect_trigger.cc
+++ b/chromium/components/safe_browsing/content/triggers/ad_redirect_trigger.cc
@@ -14,7 +14,6 @@
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
#include "components/safe_browsing/content/triggers/trigger_util.h"
#include "components/safe_browsing/core/features.h"
#include "components/safe_browsing/core/triggers/trigger_manager.h"
@@ -67,8 +66,7 @@ AdRedirectTrigger::AdRedirectTrigger(
prefs_(prefs),
url_loader_factory_(url_loader_factory),
history_service_(history_service),
- task_runner_(
- base::CreateSingleThreadTaskRunner({content::BrowserThread::UI})) {}
+ task_runner_(content::GetUIThreadTaskRunner({})) {}
AdRedirectTrigger::~AdRedirectTrigger() {}
diff --git a/chromium/components/safe_browsing/content/triggers/ad_sampler_trigger.cc b/chromium/components/safe_browsing/content/triggers/ad_sampler_trigger.cc
index afefe48ba55..7cf7372f043 100644
--- a/chromium/components/safe_browsing/content/triggers/ad_sampler_trigger.cc
+++ b/chromium/components/safe_browsing/content/triggers/ad_sampler_trigger.cc
@@ -14,7 +14,6 @@
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
#include "components/safe_browsing/content/triggers/trigger_util.h"
#include "components/safe_browsing/core/features.h"
#include "components/safe_browsing/core/triggers/trigger_manager.h"
@@ -94,8 +93,7 @@ AdSamplerTrigger::AdSamplerTrigger(
prefs_(prefs),
url_loader_factory_(url_loader_factory),
history_service_(history_service),
- task_runner_(
- base::CreateSingleThreadTaskRunner({content::BrowserThread::UI})) {}
+ task_runner_(content::GetUIThreadTaskRunner({})) {}
AdSamplerTrigger::~AdSamplerTrigger() {}
diff --git a/chromium/components/safe_browsing/content/triggers/suspicious_site_trigger.cc b/chromium/components/safe_browsing/content/triggers/suspicious_site_trigger.cc
index e531a18b18b..f144ab0f24b 100644
--- a/chromium/components/safe_browsing/content/triggers/suspicious_site_trigger.cc
+++ b/chromium/components/safe_browsing/content/triggers/suspicious_site_trigger.cc
@@ -8,7 +8,6 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
-#include "base/task/post_task.h"
#include "components/history/core/browser/history_service.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/triggers/trigger_manager.h"
@@ -68,8 +67,7 @@ SuspiciousSiteTrigger::SuspiciousSiteTrigger(
prefs_(prefs),
url_loader_factory_(url_loader_factory),
history_service_(history_service),
- task_runner_(
- base::CreateSingleThreadTaskRunner({content::BrowserThread::UI})) {}
+ task_runner_(content::GetUIThreadTaskRunner({})) {}
SuspiciousSiteTrigger::~SuspiciousSiteTrigger() {}
diff --git a/chromium/components/safe_browsing/content/web_ui/BUILD.gn b/chromium/components/safe_browsing/content/web_ui/BUILD.gn
index aa148b1849d..1658cb6b147 100644
--- a/chromium/components/safe_browsing/content/web_ui/BUILD.gn
+++ b/chromium/components/safe_browsing/content/web_ui/BUILD.gn
@@ -12,6 +12,7 @@ static_library("web_ui") {
deps = [
"//base",
+ "//components/enterprise/common/proto:connectors_proto",
"//components/password_manager/core/browser:hash_password_manager",
"//components/resources:components_resources_grit",
"//components/resources:components_scaled_resources_grit",
diff --git a/chromium/components/safe_browsing/content/web_ui/DEPS b/chromium/components/safe_browsing/content/web_ui/DEPS
index 4019a99d985..c4dfe28ac40 100644
--- a/chromium/components/safe_browsing/content/web_ui/DEPS
+++ b/chromium/components/safe_browsing/content/web_ui/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/enterprise/common/proto/connectors.pb.h",
"+components/grit/components_resources.h",
"+components/password_manager/core/browser/hash_password_manager.h",
"+components/user_prefs",
diff --git a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.css b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.css
index 6e6c6e0b70d..2d864d2f6aa 100644
--- a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.css
+++ b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.css
@@ -4,7 +4,7 @@
body {
color: rgb(48, 57, 66);
- margin:15px;
+ margin: 15px;
}
p {
white-space: pre-wrap;
@@ -13,25 +13,36 @@ p {
background-color: #fbfbfb;
border: 1px solid #cecece;
border-radius: 3px;
- padding: 19px;
line-height: 1.5;
+ padding: 19px;
}
#sb-title {
font-size: 2em;
margin-bottom: 0.8em;
}
-h1, h2, h3, p {
+h1,
+h2,
+h3,
+p {
font-weight: normal;
line-height: 1.5;
}
table.request-response {
- table-layout:fixed;
- width: 100%;
- word-break:break-all;
- white-space:pre-wrap;
border: 1px solid #cecece;
border-radius: 3px;
+ table-layout: fixed;
+ white-space: pre-wrap;
+ width: 100%;
+ word-break: break-all;
}
table.request-response td {
width: 50%;
}
+.bold-span {
+ font-weight: bold;
+}
+.result-container {
+ font-weight: normal;
+ line-height: 1.5;
+ white-space: normal;
+}
diff --git a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html
index df4d006c887..75689ec8485 100644
--- a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html
+++ b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html
@@ -35,21 +35,21 @@
<tabpanel>
<h2>Experiments</h2>
<div class="content">
- <p id="experiments-list"></p>
+ <p id="experiments-list" class="result-container"></p>
</div>
<h2>Preferences</h2>
<div class="content">
- <p id="preferences-list"></p>
+ <p id="preferences-list" class="result-container"></p>
</div>
<h2>Safe Browsing Cookie</h2>
<div class="content">
- <p id="cookie-panel"></p>
+ <p id="cookie-panel" class="result-container"></p>
</div>
</tabpanel>
<tabpanel>
<h2>Database Manager</h2>
<div class="content">
- <p id="database-info-list"></p>
+ <p id="database-info-list" class="result-container"></p>
</div>
</tabpanel>
<tabpanel>
@@ -92,7 +92,7 @@
</tabpanel>
<tabpanel>
<h2>RT Lookup Pings</h2>
- <p id="rt-lookup-experiment-enabled"></p>
+ <p id="rt-lookup-experiment-enabled" class="result-container"></p>
<table id="rt-lookup-ping-list" class="request-response"></table>
</tabpanel>
<tabpanel>
@@ -123,6 +123,24 @@
</tabpanel>
</tabpanels>
</tabbox>
+ <template id="result-template">
+ <div>
+ <span class="bold-span"></span>
+ <span></span>
+ </div>
+ </template>
+ <template id="cookie-template">
+ <div>
+ <span class="bold-span">Value: </span>
+ <span class="result"></span>
+ </div>
+ <span class="bold-span">Created: </span>
+ <span class="result"></span>
+ </template>
+ <template id="rt-lookup-template">
+ <span class="bold-span">RT Lookup Experiment Enabled: </span>
+ <span id="experiment-bool"></span>
+ </template>
<script src="safe_browsing.js"></script>
</body>
</html>
diff --git a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js
index bdb119528f1..f5ec1b4274d 100644
--- a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js
+++ b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js
@@ -161,62 +161,79 @@ cr.define('safe_browsing', function() {
function addExperiments(result) {
const resLength = result.length;
- let experimentsListFormatted = '';
for (let i = 0; i < resLength; i += 2) {
- experimentsListFormatted += "<div><b>" + result[i + 1] +
- "</b>: " + result[i] + "</div>";
+ const experimentsListFormatted =
+ $('result-template').content.cloneNode(true);
+ experimentsListFormatted.querySelectorAll('span')[0].textContent =
+ result[i + 1] + ': ';
+ experimentsListFormatted.querySelectorAll('span')[1].textContent =
+ result[i];
+ $('experiments-list').appendChild(experimentsListFormatted);
}
- $('experiments-list').innerHTML = experimentsListFormatted;
}
function addPrefs(result) {
const resLength = result.length;
- let preferencesListFormatted = "";
for (let i = 0; i < resLength; i += 2) {
- preferencesListFormatted += "<div><b>" + result[i + 1] + "</b>: " +
- result[i] + "</div>";
+ const preferencesListFormatted =
+ $('result-template').content.cloneNode(true);
+ preferencesListFormatted.querySelectorAll('span')[0].textContent =
+ result[i + 1] + ': ';
+ preferencesListFormatted.querySelectorAll('span')[1].textContent =
+ result[i];
+ $('preferences-list').appendChild(preferencesListFormatted);
}
- $('preferences-list').innerHTML = preferencesListFormatted;
}
function addCookie(result) {
- const cookieFormatted = '<b>Value:</b> ' + result[0] + '\n' +
- '<b>Created:</b> ' + (new Date(result[1])).toLocaleString();
- $('cookie-panel').innerHTML = cookieFormatted;
+ const cookieFormatted = $('cookie-template').content.cloneNode(true);
+ cookieFormatted.querySelectorAll('.result')[0].textContent = result[0];
+ cookieFormatted.querySelectorAll('.result')[1].textContent =
+ (new Date(result[1])).toLocaleString();
+ $('cookie-panel').appendChild(cookieFormatted);
}
function addSavedPasswords(result) {
const resLength = result.length;
- let savedPasswordFormatted = "";
for (let i = 0; i < resLength; i += 2) {
- savedPasswordFormatted += "<div>" + result[i];
- if (result[i+1]) {
- savedPasswordFormatted += " (GAIA password)";
- } else {
- savedPasswordFormatted += " (Enterprise password)";
- }
- savedPasswordFormatted += "</div>";
+ const savedPasswordFormatted = document.createElement('div');
+ const suffix = result[i + 1] ? 'GAIA password' : 'Enterprise password';
+ savedPasswordFormatted.textContent = `${result[i]} (${suffix})`;
+ $('saved-passwords').appendChild(savedPasswordFormatted);
}
-
- $('saved-passwords').innerHTML = savedPasswordFormatted;
}
function addDatabaseManagerInfo(result) {
const resLength = result.length;
- let preferencesListFormatted = "";
for (let i = 0; i < resLength; i += 2) {
- preferencesListFormatted += "<div><b>" + result[i] + "</b>: " +
- result[i + 1] + "</div>";
+ const preferencesListFormatted =
+ $('result-template').content.cloneNode(true);
+ preferencesListFormatted.querySelectorAll('span')[0].textContent =
+ result[i] + ': ';
+ const value = result[i + 1];
+ if (Array.isArray(value)) {
+ const blockQuote = document.createElement('blockquote');
+ value.forEach(item => {
+ const div = document.createElement('div');
+ div.textContent = item;
+ blockQuote.appendChild(div);
+ });
+ preferencesListFormatted.querySelectorAll('span')[1].appendChild(
+ blockQuote);
+ } else {
+ preferencesListFormatted.querySelectorAll('span')[1].textContent =
+ value;
+ }
+ $('database-info-list').appendChild(preferencesListFormatted);
}
- $('database-info-list').innerHTML = preferencesListFormatted;
}
function addFullHashCacheInfo(result) {
- $('full-hash-cache-info').innerHTML = result;
+ $('full-hash-cache-info').textContent = result;
}
function addSentClientDownloadRequestsInfo(result) {
@@ -307,8 +324,9 @@ cr.define('safe_browsing', function() {
}
function addRTLookupExperimentEnabled(enabled) {
- const enabledFormatted = '<b>RT Lookup Experiment Enabled:</b> ' + enabled;
- $('rt-lookup-experiment-enabled').innerHTML = enabledFormatted;
+ const enabledFormatted = $('rt-lookup-template').content.cloneNode(true);
+ enabledFormatted.querySelector('#experiment-bool').textContent = enabled;
+ $('rt-lookup-experiment-enabled').appendChild(enabledFormatted);
}
function addLogMessage(result) {
@@ -339,7 +357,8 @@ cr.define('safe_browsing', function() {
cr.sendWithPromise('getReferrerChain', $('referrer-chain-url').value)
.then((response) => {
- $('referrer-chain-content').innerHTML = response;
+ $('referrer-chain-content').innerHTML = trustedTypes.emptyHTML;
+ $('referrer-chain-content').textContent = response;
});
}
diff --git a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
index 8dd703da6b7..c04f24f0556 100644
--- a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
+++ b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
@@ -14,6 +14,7 @@
#include "base/base64url.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/i18n/number_formatting.h"
#include "base/i18n/time_formatting.h"
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ref_counted.h"
@@ -21,9 +22,9 @@
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "components/enterprise/common/proto/connectors.pb.h"
#include "components/grit/components_resources.h"
#include "components/grit/components_scaled_resources.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
@@ -219,8 +220,8 @@ void WebUIInfoSingleton::LogMessage(const std::string& message) {
base::Time timestamp = base::Time::Now();
log_messages_.push_back(std::make_pair(timestamp, message));
- base::PostTask(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&WebUIInfoSingleton::NotifyLogMessageListeners,
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(&WebUIInfoSingleton::NotifyLogMessageListeners,
timestamp, message));
}
@@ -271,6 +272,26 @@ void WebUIInfoSingleton::AddToDeepScanRequests(
request.request_token(), deep_scan_requests_[request.request_token()]);
}
+void WebUIInfoSingleton::AddToDeepScanRequests(
+ const enterprise_connectors::ContentAnalysisRequest& request) {
+ if (!HasListener())
+ return;
+
+ // Only update the request time the first time we see a token.
+ if (deep_scan_requests_.find(request.request_token()) ==
+ deep_scan_requests_.end()) {
+ deep_scan_requests_[request.request_token()].request_time =
+ base::Time::Now();
+ }
+
+ deep_scan_requests_[request.request_token()].content_analysis_request =
+ request;
+
+ for (auto* webui_listener : webui_instances_)
+ webui_listener->NotifyDeepScanJsListener(
+ request.request_token(), deep_scan_requests_[request.request_token()]);
+}
+
void WebUIInfoSingleton::AddToDeepScanResponses(
const std::string& token,
const std::string& status,
@@ -286,6 +307,21 @@ void WebUIInfoSingleton::AddToDeepScanResponses(
webui_listener->NotifyDeepScanJsListener(token, deep_scan_requests_[token]);
}
+void WebUIInfoSingleton::AddToDeepScanResponses(
+ const std::string& token,
+ const std::string& status,
+ const enterprise_connectors::ContentAnalysisResponse& response) {
+ if (!HasListener())
+ return;
+
+ deep_scan_requests_[token].response_time = base::Time::Now();
+ deep_scan_requests_[token].response_status = status;
+ deep_scan_requests_[token].content_analysis_response = response;
+
+ for (auto* webui_listener : webui_instances_)
+ webui_listener->NotifyDeepScanJsListener(token, deep_scan_requests_[token]);
+}
+
void WebUIInfoSingleton::ClearDeepScans() {
base::flat_map<std::string, DeepScanDebugData>().swap(deep_scan_requests_);
}
@@ -369,34 +405,33 @@ void AddStoreInfo(const DatabaseManagerInfo::DatabaseInfo::StoreInfo store_info,
database_info_list->Append(base::Value("Unknown store"));
}
- std::string store_info_string = "<blockquote>";
+ base::Value store_info_list(base::Value::Type::LIST);
if (store_info.has_file_size_bytes()) {
- store_info_string +=
- "Size (in bytes): " + std::to_string(store_info.file_size_bytes()) +
- "<br>";
+ store_info_list.Append(
+ "Size (in bytes): " +
+ base::UTF16ToUTF8(base::FormatNumber(store_info.file_size_bytes())));
}
if (store_info.has_update_status()) {
- store_info_string +=
- "Update status: " + std::to_string(store_info.update_status()) + "<br>";
+ store_info_list.Append(
+ "Update status: " +
+ base::UTF16ToUTF8(base::FormatNumber(store_info.update_status())));
}
if (store_info.has_last_apply_update_time_millis()) {
- store_info_string += "Last update time: " +
- UserReadableTimeFromMillisSinceEpoch(
- store_info.last_apply_update_time_millis())
- .GetString() +
- "<br>";
+ store_info_list.Append("Last update time: " +
+ UserReadableTimeFromMillisSinceEpoch(
+ store_info.last_apply_update_time_millis())
+ .GetString());
}
if (store_info.has_checks_attempted()) {
- store_info_string += "Number of database checks: " +
- std::to_string(store_info.checks_attempted()) + "<br>";
+ store_info_list.Append(
+ "Number of database checks: " +
+ base::UTF16ToUTF8(base::FormatNumber(store_info.checks_attempted())));
}
- store_info_string += "</blockquote>";
-
- database_info_list->Append(base::Value(store_info_string));
+ database_info_list->Append(std::move(store_info_list));
}
void AddDatabaseInfo(const DatabaseManagerInfo::DatabaseInfo database_info,
@@ -1304,6 +1339,52 @@ base::Value SerializeReportingEvent(const base::Value& event) {
}
#if BUILDFLAG(FULL_SAFE_BROWSING)
+std::string SerializeContentAnalysisRequest(
+ const enterprise_connectors::ContentAnalysisRequest& request) {
+ base::DictionaryValue request_dict;
+
+ request_dict.SetKey("device_token", base::Value(request.device_token()));
+ request_dict.SetKey("fcm_notification_token",
+ base::Value(request.fcm_notification_token()));
+ switch (request.analysis_connector()) {
+ case enterprise_connectors::ANALYSIS_CONNECTOR_UNSPECIFIED:
+ request_dict.SetStringKey("analysis_connector", "UNSPECIFIED");
+ break;
+ case enterprise_connectors::FILE_ATTACHED:
+ request_dict.SetStringKey("analysis_connector", "FILE_ATTACHED");
+ break;
+ case enterprise_connectors::FILE_DOWNLOADED:
+ request_dict.SetStringKey("analysis_connector", "FILE_DOWNLOADED");
+ break;
+ case enterprise_connectors::BULK_DATA_ENTRY:
+ request_dict.SetStringKey("analysis_connector", "BULK_DATA_ENTRY");
+ break;
+ }
+
+ if (request.has_request_data()) {
+ base::DictionaryValue request_data;
+ request_data.SetStringKey("url", request.request_data().url());
+ request_data.SetStringKey("filename", request.request_data().filename());
+ request_data.SetStringKey("digest", request.request_data().digest());
+ // TODO(domfc): Improve this once csd is populated for this proto.
+ request_data.SetStringKey("csd",
+ request.request_data().csd().SerializeAsString());
+ request_dict.SetKey("request_data", std::move(request_data));
+ }
+
+ base::ListValue tags;
+ for (const std::string& tag : request.tags())
+ tags.Append(base::Value(tag));
+ request_dict.SetKey("tags", std::move(tags));
+ request_dict.SetKey("request_token", base::Value(request.request_token()));
+
+ std::string request_serialized;
+ JSONStringValueSerializer serializer(&request_serialized);
+ serializer.set_pretty_print(true);
+ serializer.Serialize(request_dict);
+ return request_serialized;
+}
+
std::string SerializeDeepScanningRequest(
const DeepScanningClientRequest& request) {
base::DictionaryValue request_dict;
@@ -1362,6 +1443,68 @@ std::string SerializeDeepScanningRequest(
return request_serialized;
}
+std::string SerializeContentAnalysisResponse(
+ const enterprise_connectors::ContentAnalysisResponse& response) {
+ base::DictionaryValue response_dict;
+
+ response_dict.SetStringKey("token", response.request_token());
+
+ base::ListValue result_values;
+ for (const auto& result : response.results()) {
+ base::DictionaryValue result_value;
+ switch (result.status()) {
+ case enterprise_connectors::ContentAnalysisResponse::Result::
+ STATUS_UNKNOWN:
+ result_value.SetStringKey("status", "STATUS_UNKNOWN");
+ break;
+ case enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS:
+ result_value.SetStringKey("status", "SUCCESS");
+ break;
+ case enterprise_connectors::ContentAnalysisResponse::Result::FAILURE:
+ result_value.SetStringKey("status", "FAILURE");
+ break;
+ }
+ result_value.SetStringKey("tag", result.tag());
+
+ base::ListValue triggered_rules;
+ for (const auto& rule : result.triggered_rules()) {
+ base::DictionaryValue rule_value;
+
+ switch (rule.action()) {
+ case enterprise_connectors::ContentAnalysisResponse::Result::
+ TriggeredRule::ACTION_UNSPECIFIED:
+ rule_value.SetStringKey("action", "ACTION_UNSPECIFIED");
+ break;
+ case enterprise_connectors::ContentAnalysisResponse::Result::
+ TriggeredRule::REPORT_ONLY:
+ rule_value.SetStringKey("action", "REPORT_ONLY");
+ break;
+ case enterprise_connectors::ContentAnalysisResponse::Result::
+ TriggeredRule::WARN:
+ rule_value.SetStringKey("action", "WARN");
+ break;
+ case enterprise_connectors::ContentAnalysisResponse::Result::
+ TriggeredRule::BLOCK:
+ rule_value.SetStringKey("action", "BLOCK");
+ break;
+ }
+
+ rule_value.SetStringKey("rule_name", rule.rule_name());
+ rule_value.SetStringKey("rule_id", rule.rule_id());
+ triggered_rules.Append(std::move(rule_value));
+ }
+ result_value.SetKey("triggered_rules", std::move(triggered_rules));
+ result_values.Append(std::move(result_value));
+ }
+ response_dict.SetKey("results", std::move(result_values));
+
+ std::string response_serialized;
+ JSONStringValueSerializer serializer(&response_serialized);
+ serializer.set_pretty_print(true);
+ serializer.Serialize(response_dict);
+ return response_serialized;
+}
+
std::string SerializeDeepScanningResponse(
const DeepScanningClientResponse& response) {
base::DictionaryValue response_dict;
@@ -1471,6 +1614,9 @@ base::Value SerializeDeepScanDebugData(const std::string& token,
if (data.request.has_value()) {
value.SetStringKey("request",
SerializeDeepScanningRequest(data.request.value()));
+ } else if (data.content_analysis_request.has_value()) {
+ value.SetStringKey("request", SerializeContentAnalysisRequest(
+ data.content_analysis_request.value()));
}
if (!data.response_time.is_null()) {
@@ -1484,6 +1630,9 @@ base::Value SerializeDeepScanDebugData(const std::string& token,
if (data.response.has_value()) {
value.SetStringKey("response",
SerializeDeepScanningResponse(data.response.value()));
+ } else if (data.content_analysis_response.has_value()) {
+ value.SetStringKey("response", SerializeContentAnalysisResponse(
+ data.content_analysis_response.value()));
}
return std::move(value);
diff --git a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h
index d7b296688be..8e10f4700ff 100644
--- a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h
+++ b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "components/enterprise/common/proto/connectors.pb.h"
#include "components/safe_browsing/buildflags.h"
#include "components/safe_browsing/core/browser/safe_browsing_network_context.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
@@ -42,10 +43,14 @@ struct DeepScanDebugData {
base::Time request_time;
base::Optional<DeepScanningClientRequest> request;
+ base::Optional<enterprise_connectors::ContentAnalysisRequest>
+ content_analysis_request;
base::Time response_time;
std::string response_status;
base::Optional<DeepScanningClientResponse> response;
+ base::Optional<enterprise_connectors::ContentAnalysisResponse>
+ content_analysis_response;
};
#endif
@@ -327,12 +332,18 @@ class WebUIInfoSingleton {
// identifier that can be used in |AddToDeepScanResponses| to correlate a ping
// and response.
void AddToDeepScanRequests(const DeepScanningClientRequest& request);
+ void AddToDeepScanRequests(
+ const enterprise_connectors::ContentAnalysisRequest& request);
// Add the new response to |deep_scan_requests_| and send it to all the open
// chrome://safe-browsing tabs.
void AddToDeepScanResponses(const std::string& token,
const std::string& status,
const DeepScanningClientResponse& response);
+ void AddToDeepScanResponses(
+ const std::string& token,
+ const std::string& status,
+ const enterprise_connectors::ContentAnalysisResponse& response);
// Clear the list of deep scan requests and responses.
void ClearDeepScans();