Commit d5f38c7e authored by Livvie Lin's avatar Livvie Lin Committed by Commit Bot

[iOS] Add LookalikeUrlBlockingPage and LookalikeUrlControllerClient

A follow-up CL will create the blocking page and controller client
in ChromeWebClient to show the UI.

Bug: 1058898
Change-Id: I1709a6bba4accd22089ea24ef5183a6101c27bdf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2261364Reviewed-by: default avatarAli Juma <ajuma@chromium.org>
Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Commit-Queue: Livvie Lin <livvielin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#784543}
parent a75fe375
...@@ -33,6 +33,10 @@ class IOSBlockingPageControllerClient ...@@ -33,6 +33,10 @@ class IOSBlockingPageControllerClient
const std::string& app_locale); const std::string& app_locale);
~IOSBlockingPageControllerClient() override; ~IOSBlockingPageControllerClient() override;
// security_interstitials::ControllerClient implementation.
void Proceed() override;
void GoBack() override;
void SetWebInterstitial(web::WebInterstitial* web_interstitial); void SetWebInterstitial(web::WebInterstitial* web_interstitial);
// web::WebStateObserver implementation. // web::WebStateObserver implementation.
...@@ -40,6 +44,10 @@ class IOSBlockingPageControllerClient ...@@ -40,6 +44,10 @@ class IOSBlockingPageControllerClient
const std::string& GetApplicationLocale() const override; const std::string& GetApplicationLocale() const override;
// Closes the tab. Called in cases where a user clicks "Back to safety" and
// it's not possible to go back.
void Close();
protected: protected:
// The WebState passed on initialization. // The WebState passed on initialization.
web::WebState* web_state() const { return web_state_; } web::WebState* web_state() const { return web_state_; }
...@@ -47,11 +55,9 @@ class IOSBlockingPageControllerClient ...@@ -47,11 +55,9 @@ class IOSBlockingPageControllerClient
// security_interstitials::ControllerClient implementation. // security_interstitials::ControllerClient implementation.
bool CanLaunchDateAndTimeSettings() override; bool CanLaunchDateAndTimeSettings() override;
void LaunchDateAndTimeSettings() override; void LaunchDateAndTimeSettings() override;
void GoBack() override;
bool CanGoBack() override; bool CanGoBack() override;
bool CanGoBackBeforeNavigation() override; bool CanGoBackBeforeNavigation() override;
void GoBackAfterNavigationCommitted() override; void GoBackAfterNavigationCommitted() override;
void Proceed() override;
void Reload() override; void Reload() override;
void OpenUrlInCurrentTab(const GURL& url) override; void OpenUrlInCurrentTab(const GURL& url) override;
void OpenUrlInNewForegroundTab(const GURL& url) override; void OpenUrlInNewForegroundTab(const GURL& url) override;
...@@ -59,10 +65,6 @@ class IOSBlockingPageControllerClient ...@@ -59,10 +65,6 @@ class IOSBlockingPageControllerClient
const std::string GetExtendedReportingPrefName() const override; const std::string GetExtendedReportingPrefName() const override;
private: private:
// Closes the tab. Called in cases where a user clicks "Back to safety" and
// it's not possible to go back.
void Close();
web::WebState* web_state_; web::WebState* web_state_;
web::WebInterstitial* web_interstitial_; web::WebInterstitial* web_interstitial_;
const std::string app_locale_; const std::string app_locale_;
......
...@@ -5,8 +5,12 @@ ...@@ -5,8 +5,12 @@
source_set("lookalikes") { source_set("lookalikes") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
sources = [ sources = [
"lookalike_url_blocking_page.h",
"lookalike_url_blocking_page.mm",
"lookalike_url_container.h", "lookalike_url_container.h",
"lookalike_url_container.mm", "lookalike_url_container.mm",
"lookalike_url_controller_client.h",
"lookalike_url_controller_client.mm",
"lookalike_url_error.h", "lookalike_url_error.h",
"lookalike_url_error.mm", "lookalike_url_error.mm",
"lookalike_url_tab_allow_list.h", "lookalike_url_tab_allow_list.h",
...@@ -18,22 +22,31 @@ source_set("lookalikes") { ...@@ -18,22 +22,31 @@ source_set("lookalikes") {
"//base", "//base",
"//components/lookalikes/core", "//components/lookalikes/core",
"//components/security_interstitials/core", "//components/security_interstitials/core",
"//components/ukm/ios",
"//components/url_formatter/spoof_checks/top_domains:common", "//components/url_formatter/spoof_checks/top_domains:common",
"//ios/components/security_interstitials", "//ios/components/security_interstitials",
"//ios/net", "//ios/net",
"//ios/web/public", "//ios/web/public",
"//net", "//net",
"//services/metrics/public/cpp:metrics_cpp",
] ]
} }
source_set("unit_tests") { source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
testonly = true testonly = true
sources = [ "lookalike_url_tab_helper_unittest.mm" ] sources = [
"lookalike_url_blocking_page_unittest.mm",
"lookalike_url_tab_helper_unittest.mm",
]
deps = [ deps = [
":lookalikes", ":lookalikes",
"//base/test:test_support",
"//components/lookalikes/core",
"//ios/web/public",
"//ios/web/public/test", "//ios/web/public/test",
"//net", "//net",
"//services/metrics/public/cpp:metrics_cpp",
"//testing/gtest", "//testing/gtest",
] ]
} }
include_rules = [ include_rules = [
"+components/lookalikes/core", "+components/lookalikes/core",
"+components/ukm/ios",
"+components/url_formatter", "+components/url_formatter",
"+ios/net", "+ios/net",
"+net/base", "+net/base",
"+services/metrics/public/cpp",
] ]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_BLOCKING_PAGE_H_
#define IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_BLOCKING_PAGE_H_
#include "components/lookalikes/core/lookalike_url_util.h"
#include "ios/components/security_interstitials/ios_security_interstitial_page.h"
#include "ios/components/security_interstitials/lookalikes/lookalike_url_controller_client.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
class GURL;
// This class is responsible for showing/hiding the interstitial page that is
// shown on a lookalike URL.
class LookalikeUrlBlockingPage
: public security_interstitials::IOSSecurityInterstitialPage {
public:
~LookalikeUrlBlockingPage() override;
// Creates a lookalike URL blocking page.
LookalikeUrlBlockingPage(
web::WebState* web_state,
const GURL& safe_url,
const GURL& request_url,
ukm::SourceId source_id,
LookalikeUrlMatchType match_type,
std::unique_ptr<LookalikeUrlControllerClient> client);
protected:
// SecurityInterstitialPage implementation:
bool ShouldCreateNewNavigation() const override;
void PopulateInterstitialStrings(
base::DictionaryValue* load_time_data) const override;
private:
void HandleScriptCommand(const base::DictionaryValue& message,
const GURL& origin_url,
bool user_is_interacting,
web::WebFrame* sender_frame) override;
void AfterShow() override;
web::WebState* web_state_ = nullptr;
std::unique_ptr<LookalikeUrlControllerClient> controller_;
// The URL suggested to the user as the safe URL. Can be empty, in which case
// the default action on the interstitial is to close the tab.
const GURL safe_url_;
ukm::SourceId source_id_;
LookalikeUrlMatchType match_type_;
DISALLOW_COPY_AND_ASSIGN(LookalikeUrlBlockingPage);
};
#endif // IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_BLOCKING_PAGE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/components/security_interstitials/lookalikes/lookalike_url_blocking_page.h"
#include <utility>
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "components/lookalikes/core/lookalike_url_ui_util.h"
#include "components/lookalikes/core/lookalike_url_util.h"
#include "components/security_interstitials/core/common_string_util.h"
#include "components/security_interstitials/core/metrics_helper.h"
#include "ios/components/security_interstitials/ios_blocking_page_controller_client.h"
#include "ios/components/security_interstitials/ios_blocking_page_metrics_helper.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
LookalikeUrlBlockingPage::LookalikeUrlBlockingPage(
web::WebState* web_state,
const GURL& safe_url,
const GURL& request_url,
ukm::SourceId source_id,
LookalikeUrlMatchType match_type,
std::unique_ptr<LookalikeUrlControllerClient> client)
: security_interstitials::IOSSecurityInterstitialPage(web_state,
request_url,
client.get()),
web_state_(web_state),
controller_(std::move(client)),
safe_url_(safe_url),
source_id_(source_id),
match_type_(match_type) {
DCHECK(web_state_);
// Creating an interstitial without showing it (e.g. from
// chrome://interstitials) leaks memory, so don't create it here.
}
LookalikeUrlBlockingPage::~LookalikeUrlBlockingPage() = default;
bool LookalikeUrlBlockingPage::ShouldCreateNewNavigation() const {
return true;
}
void LookalikeUrlBlockingPage::PopulateInterstitialStrings(
base::DictionaryValue* load_time_data) const {
CHECK(load_time_data);
PopulateLookalikeUrlBlockingPageStrings(load_time_data, safe_url_);
}
void LookalikeUrlBlockingPage::HandleScriptCommand(
const base::DictionaryValue& message,
const GURL& origin_url,
bool user_is_interacting,
web::WebFrame* sender_frame) {
std::string command_string;
if (!message.GetString("command", &command_string)) {
LOG(ERROR) << "JS message parameter not found: command";
return;
}
// Remove the command prefix so that the string value can be converted to a
// SecurityInterstitialCommand enum value.
std::size_t delimiter = command_string.find(".");
if (delimiter == std::string::npos) {
return;
}
// Parse the command int value from the text after the delimiter.
int command = 0;
if (!base::StringToInt(command_string.substr(delimiter + 1), &command)) {
NOTREACHED() << "Command cannot be parsed to an int : " << command_string;
return;
}
if (command == security_interstitials::CMD_DONT_PROCEED) {
controller_->metrics_helper()->RecordUserDecision(
security_interstitials::MetricsHelper::DONT_PROCEED);
ReportUkmForLookalikeUrlBlockingPageIfNeeded(
source_id_, match_type_,
LookalikeUrlBlockingPageUserAction::kAcceptSuggestion);
// If the interstitial doesn't have a suggested URL (e.g. punycode
// interstitial), close the tab.
if (!safe_url_.is_valid()) {
controller_->Close();
} else {
controller_->GoBack();
}
} else if (command == security_interstitials::CMD_PROCEED) {
controller_->metrics_helper()->RecordUserDecision(
security_interstitials::MetricsHelper::PROCEED);
ReportUkmForLookalikeUrlBlockingPageIfNeeded(
source_id_, match_type_,
LookalikeUrlBlockingPageUserAction::kClickThrough);
controller_->Proceed();
}
}
void LookalikeUrlBlockingPage::AfterShow() {}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/components/security_interstitials/lookalikes/lookalike_url_blocking_page.h"
#include "base/strings/string_number_conversions.h"
#import "base/test/ios/wait_util.h"
#include "base/values.h"
#include "components/lookalikes/core/lookalike_url_util.h"
#include "ios/components/security_interstitials/lookalikes/lookalike_url_controller_client.h"
#include "ios/components/security_interstitials/lookalikes/lookalike_url_tab_allow_list.h"
#import "ios/web/public/navigation/navigation_item.h"
#import "ios/web/public/test/fakes/test_navigation_manager.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/web_task_environment.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using security_interstitials::IOSSecurityInterstitialPage;
using security_interstitials::SecurityInterstitialCommand;
using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kSpinDelaySeconds;
namespace {
// Creates a LookalikeUrlBlockingPage with a given |safe_url|.
std::unique_ptr<LookalikeUrlBlockingPage> CreateBlockingPage(
web::WebState* web_state,
const GURL& safe_url,
const GURL& request_url) {
return std::make_unique<LookalikeUrlBlockingPage>(
web_state, safe_url, request_url, ukm::kInvalidSourceId,
LookalikeUrlMatchType::kSkeletonMatchTop500,
std::make_unique<LookalikeUrlControllerClient>(web_state, safe_url,
request_url, "en-US"));
}
} // namespace
// A Test web state that sets the visible URL to the last opened URL.
class TestWebState : public web::TestWebState {
public:
void OpenURL(const web::WebState::OpenURLParams& params) override {
SetVisibleURL(params.url);
}
};
// Test fixture for SafeBrowsingBlockingPage.
class LookalikeUrlBlockingPageTest : public PlatformTest {
public:
LookalikeUrlBlockingPageTest() : url_("https://www.chromium.test") {
std::unique_ptr<web::TestNavigationManager> navigation_manager =
std::make_unique<web::TestNavigationManager>();
navigation_manager_ = navigation_manager.get();
web_state_.SetNavigationManager(std::move(navigation_manager));
LookalikeUrlTabAllowList::CreateForWebState(&web_state_);
LookalikeUrlTabAllowList::FromWebState(&web_state_);
}
void SendCommand(SecurityInterstitialCommand command) {
base::DictionaryValue dict;
dict.SetKey("command", base::Value("." + base::NumberToString(command)));
page_->HandleScriptCommand(dict, url_,
/*user_is_interacting=*/true,
/*sender_frame=*/nullptr);
}
protected:
web::WebTaskEnvironment task_environment_{
web::WebTaskEnvironment::IO_MAINLOOP};
TestWebState web_state_;
web::TestNavigationManager* navigation_manager_ = nullptr;
GURL url_;
std::unique_ptr<IOSSecurityInterstitialPage> page_;
};
// Tests that the blocking page handles the proceed command by updating the
// allow list and reloading the page.
TEST_F(LookalikeUrlBlockingPageTest, HandleProceedCommand) {
GURL safe_url("https://www.safe.test");
page_ = CreateBlockingPage(&web_state_, safe_url, url_);
LookalikeUrlTabAllowList* allow_list =
LookalikeUrlTabAllowList::FromWebState(&web_state_);
ASSERT_FALSE(allow_list->IsDomainAllowed(url_.host()));
ASSERT_FALSE(navigation_manager_->ReloadWasCalled());
// Send the proceed command.
SendCommand(security_interstitials::CMD_PROCEED);
EXPECT_TRUE(allow_list->IsDomainAllowed(url_.host()));
EXPECT_TRUE(navigation_manager_->ReloadWasCalled());
}
// Tests that the blocking page handles the don't proceed command by navigating
// to the suggested URL.
TEST_F(LookalikeUrlBlockingPageTest, HandleDontProceedCommand) {
GURL safe_url("https://www.safe.test");
// Add a navigation for the committed interstitial page so that navigation to
// the safe URL can later be verified.
navigation_manager_->AddItem(url_, ui::PAGE_TRANSITION_LINK);
page_ = CreateBlockingPage(&web_state_, safe_url, url_);
// Send the don't proceed command.
SendCommand(security_interstitials::CMD_DONT_PROCEED);
EXPECT_EQ(web_state_.GetVisibleURL(), safe_url);
}
// Tests that the blocking page handles the don't proceed command by closing the
// WebState if there is no safe NavigationItem to navigate back to.
TEST_F(LookalikeUrlBlockingPageTest, HandleDontProceedCommandWithoutSafeUrl) {
GURL empty_safe_url("");
page_ = CreateBlockingPage(&web_state_, empty_safe_url, url_);
// Send the don't proceed command.
SendCommand(security_interstitials::CMD_DONT_PROCEED);
// Wait for the WebState to be closed. The close command run asynchronously
// on the UI thread, so the runloop needs to be spun before it is handled.
task_environment_.RunUntilIdle();
EXPECT_TRUE(WaitUntilConditionOrTimeout(kSpinDelaySeconds, ^{
return web_state_.IsClosed();
}));
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "components/lookalikes/core/lookalike_url_util.h"
#include "ios/web/public/navigation/referrer.h" #include "ios/web/public/navigation/referrer.h"
#import "ios/web/public/web_state_user_data.h" #import "ios/web/public/web_state_user_data.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -42,6 +43,19 @@ class LookalikeUrlContainer ...@@ -42,6 +43,19 @@ class LookalikeUrlContainer
~InterstitialParams(); ~InterstitialParams();
}; };
// Structure that contains information for the lookalike URL blocking page UI.
struct LookalikeUrlInfo {
const GURL safe_url;
const GURL request_url;
LookalikeUrlMatchType match_type;
LookalikeUrlInfo(const GURL& safe_url,
const GURL& request_url,
LookalikeUrlMatchType match_type);
LookalikeUrlInfo(const LookalikeUrlInfo& other);
~LookalikeUrlInfo();
};
// Stores parameters associated with a lookalike blocking page. Must be called // Stores parameters associated with a lookalike blocking page. Must be called
// when a lookalike blocking page is shown. // when a lookalike blocking page is shown.
void RecordLookalikeBlockingPageParams( void RecordLookalikeBlockingPageParams(
...@@ -49,10 +63,19 @@ class LookalikeUrlContainer ...@@ -49,10 +63,19 @@ class LookalikeUrlContainer
const web::Referrer& referrer, const web::Referrer& referrer,
const std::vector<GURL>& redirect_chain); const std::vector<GURL>& redirect_chain);
// Stores URL info associated with a lookalike blocking page.
void SetLookalikeUrlInfo(const GURL& safe_url,
const GURL& request_url,
LookalikeUrlMatchType match_type);
// Returns currently stored parameters associated with a lookalike blocking // Returns currently stored parameters associated with a lookalike blocking
// page, transferring ownership to the caller. // page, transferring ownership to the caller.
std::unique_ptr<InterstitialParams> ReleaseInterstitialParams(); std::unique_ptr<InterstitialParams> ReleaseInterstitialParams();
// Returns currently stored URL info associated with a lookalike blocking
// page, transferring ownership to the caller.
std::unique_ptr<LookalikeUrlInfo> ReleaseLookalikeUrlInfo();
private: private:
explicit LookalikeUrlContainer(web::WebState* web_state); explicit LookalikeUrlContainer(web::WebState* web_state);
friend class web::WebStateUserData<LookalikeUrlContainer>; friend class web::WebStateUserData<LookalikeUrlContainer>;
...@@ -61,6 +84,10 @@ class LookalikeUrlContainer ...@@ -61,6 +84,10 @@ class LookalikeUrlContainer
// Parameters associated with the currently displayed blocking page. These are // Parameters associated with the currently displayed blocking page. These are
// cleared immediately on next navigation. // cleared immediately on next navigation.
std::unique_ptr<InterstitialParams> interstitial_params_; std::unique_ptr<InterstitialParams> interstitial_params_;
// Lookalike URL info associated with the currently displayed blocking page.
// These are cleared immediately on next navigation.
std::unique_ptr<LookalikeUrlInfo> lookalike_info_;
}; };
#endif // IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_CONTAINER_H_ #endif // IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_CONTAINER_H_
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h" #import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "components/lookalikes/core/lookalike_url_util.h"
#import "ios/web/public/web_state.h" #import "ios/web/public/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
...@@ -30,6 +31,17 @@ LookalikeUrlContainer::InterstitialParams::~InterstitialParams() = default; ...@@ -30,6 +31,17 @@ LookalikeUrlContainer::InterstitialParams::~InterstitialParams() = default;
LookalikeUrlContainer::InterstitialParams::InterstitialParams( LookalikeUrlContainer::InterstitialParams::InterstitialParams(
const InterstitialParams& other) = default; const InterstitialParams& other) = default;
LookalikeUrlContainer::LookalikeUrlInfo::LookalikeUrlInfo(
const GURL& safe_url,
const GURL& request_url,
LookalikeUrlMatchType match_type)
: safe_url(safe_url), request_url(request_url), match_type(match_type) {}
LookalikeUrlContainer::LookalikeUrlInfo::~LookalikeUrlInfo() {}
LookalikeUrlContainer::LookalikeUrlInfo::LookalikeUrlInfo(
const LookalikeUrlInfo& other) = default;
void LookalikeUrlContainer::RecordLookalikeBlockingPageParams( void LookalikeUrlContainer::RecordLookalikeBlockingPageParams(
const GURL& url, const GURL& url,
const web::Referrer& referrer, const web::Referrer& referrer,
...@@ -39,7 +51,20 @@ void LookalikeUrlContainer::RecordLookalikeBlockingPageParams( ...@@ -39,7 +51,20 @@ void LookalikeUrlContainer::RecordLookalikeBlockingPageParams(
interstitial_params_->redirect_chain = redirect_chain; interstitial_params_->redirect_chain = redirect_chain;
} }
void LookalikeUrlContainer::SetLookalikeUrlInfo(
const GURL& safe_url,
const GURL& request_url,
LookalikeUrlMatchType match_type) {
lookalike_info_ =
std::make_unique<LookalikeUrlInfo>(safe_url, request_url, match_type);
}
std::unique_ptr<LookalikeUrlContainer::InterstitialParams> std::unique_ptr<LookalikeUrlContainer::InterstitialParams>
LookalikeUrlContainer::ReleaseInterstitialParams() { LookalikeUrlContainer::ReleaseInterstitialParams() {
return std::move(interstitial_params_); return std::move(interstitial_params_);
} }
std::unique_ptr<LookalikeUrlContainer::LookalikeUrlInfo>
LookalikeUrlContainer::ReleaseLookalikeUrlInfo() {
return std::move(lookalike_info_);
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_CONTROLLER_CLIENT_H_
#define IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_CONTROLLER_CLIENT_H_
#include "base/memory/weak_ptr.h"
#include "ios/components/security_interstitials/ios_blocking_page_controller_client.h"
#include "url/gurl.h"
class GURL;
namespace web {
class WebState;
} // namespace web
// Controller client used for lookalike URL blocking pages.
class LookalikeUrlControllerClient
: public security_interstitials::IOSBlockingPageControllerClient {
public:
LookalikeUrlControllerClient(web::WebState* web_state,
const GURL& safe_url,
const GURL& request_url,
const std::string& app_locale);
~LookalikeUrlControllerClient() override;
// security_interstitials::ControllerClient:
void Proceed() override;
void GoBack() override;
// Closes the tab. Called in cases where there is no suggested URL.
void Close();
private:
// The URL suggested to the user as the safe URL. Can be empty, in which case
// the default action on the interstitial closes the tab.
const GURL safe_url_;
// The URL of the page causing the insterstitial.
const GURL request_url_;
base::WeakPtrFactory<LookalikeUrlControllerClient> weak_factory_;
};
#endif // IOS_COMPONENTS_SECURITY_INTERSTITIALS_LOOKALIKES_LOOKALIKE_URL_CONTROLLER_CLIENT_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/components/security_interstitials/lookalikes/lookalike_url_controller_client.h"
#include "base/bind.h"
#include "base/task/post_task.h"
#include "components/security_interstitials/core/metrics_helper.h"
#include "ios/components/security_interstitials/ios_blocking_page_metrics_helper.h"
#include "ios/components/security_interstitials/lookalikes/lookalike_url_tab_allow_list.h"
#include "ios/web/public/thread/web_task_traits.h"
#include "ios/web/public/thread/web_thread.h"
#import "ios/web/public/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Creates a metrics helper for |url|.
std::unique_ptr<security_interstitials::IOSBlockingPageMetricsHelper>
CreateMetricsHelper(web::WebState* web_state, const GURL& url) {
security_interstitials::MetricsHelper::ReportDetails reporting_info;
reporting_info.metric_prefix = "lookalike";
return std::make_unique<security_interstitials::IOSBlockingPageMetricsHelper>(
web_state, url, reporting_info);
}
} // namespace
LookalikeUrlControllerClient::LookalikeUrlControllerClient(
web::WebState* web_state,
const GURL& safe_url,
const GURL& request_url,
const std::string& app_locale)
: IOSBlockingPageControllerClient(
web_state,
CreateMetricsHelper(web_state, request_url),
app_locale),
safe_url_(safe_url),
request_url_(request_url),
weak_factory_(this) {}
LookalikeUrlControllerClient::~LookalikeUrlControllerClient() {}
void LookalikeUrlControllerClient::GoBack() {
// Instead of a 'go back' option, redirect to the legitimate site.
OpenUrlInCurrentTab(safe_url_);
}
void LookalikeUrlControllerClient::Proceed() {
LookalikeUrlTabAllowList::FromWebState(web_state())
->AllowDomain(request_url_.host());
Reload();
}
void LookalikeUrlControllerClient::Close() {
// Closing the tab synchronously is problematic since web state is heavily
// involved in the operation and CloseWebState interrupts it, so call
// CloseWebState asynchronously.
base::PostTask(FROM_HERE, {web::WebThread::UI},
base::BindOnce(&IOSBlockingPageControllerClient::Close,
weak_factory_.GetWeakPtr()));
}
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
#import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.h" #import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.h"
#include "components/lookalikes/core/lookalike_url_ui_util.h"
#include "components/lookalikes/core/lookalike_url_util.h" #include "components/lookalikes/core/lookalike_url_util.h"
#include "components/ukm/ios/ukm_url_recorder.h"
#include "components/url_formatter/spoof_checks/top_domains/top_domain_util.h" #include "components/url_formatter/spoof_checks/top_domains/top_domain_util.h"
#include "ios/components/security_interstitials/lookalikes/lookalike_url_container.h" #include "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
#include "ios/components/security_interstitials/lookalikes/lookalike_url_error.h" #include "ios/components/security_interstitials/lookalikes/lookalike_url_error.h"
...@@ -107,19 +109,24 @@ void LookalikeUrlTabHelper::ShouldAllowResponse( ...@@ -107,19 +109,24 @@ void LookalikeUrlTabHelper::ShouldAllowResponse(
DCHECK(!matched_domain.empty()); DCHECK(!matched_domain.empty());
if (ShouldBlockLookalikeUrlNavigation(match_type, navigated_domain)) { if (ShouldBlockLookalikeUrlNavigation(match_type, navigated_domain)) {
// TODO(crbug.com/1058898): Use the below information to generate the
// blocking page UI.
const std::string suggested_domain = GetETLDPlusOne(matched_domain); const std::string suggested_domain = GetETLDPlusOne(matched_domain);
DCHECK(!suggested_domain.empty()); DCHECK(!suggested_domain.empty());
GURL::Replacements replace_host; GURL::Replacements replace_host;
replace_host.SetHostStr(suggested_domain); replace_host.SetHostStr(suggested_domain);
const GURL suggested_url = const GURL suggested_url =
response_url.ReplaceComponents(replace_host).GetWithEmptyPath(); response_url.ReplaceComponents(replace_host).GetWithEmptyPath();
lookalike_container->SetLookalikeUrlInfo(suggested_url, response_url,
match_type);
std::move(callback).Run(CreateLookalikeErrorDecision()); std::move(callback).Run(CreateLookalikeErrorDecision());
return; return;
} }
// Interstitial normally records UKM, but still record when it's not shown.
RecordUkmForLookalikeUrlBlockingPage(
ukm::GetSourceIdForWebStateDocument(web_state()), match_type,
LookalikeUrlBlockingPageUserAction::kInterstitialNotShown);
std::move(callback).Run(CreateAllowDecision()); std::move(callback).Run(CreateAllowDecision());
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment