Commit 2bd6fe9a authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Hook up chrome://interstitials page.

This CL adds support for the chrome://interstitials WebUI, which
contains links for dummy interstitials.  Currently only a subset of the
available links are implemented for iOS.

Bug: 1064803
Change-Id: Ie8fed45623f18319ff1c8a9de5108108a796b2bf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2145154
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Auto-Submit: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#758619}
parent 16898cbc
......@@ -14,6 +14,7 @@ const char kChromeUICreditsURL[] = "chrome://credits/";
const char kChromeUIFlagsURL[] = "chrome://flags/";
const char kChromeUIHistoryURL[] = "chrome://history/";
const char kChromeUIInspectURL[] = "chrome://inspect/";
const char kChromeUIIntersitialsURL[] = "chrome://interstitials";
const char kChromeUINewTabURL[] = "chrome://newtab/";
const char kChromeUINTPTilesInternalsURL[] = "chrome://ntp-tiles-internals/";
const char kChromeUIOfflineURL[] = "chrome://offline/";
......@@ -35,6 +36,7 @@ const char kChromeUIGCMInternalsHost[] = "gcm-internals";
const char kChromeUIHistogramHost[] = "histograms";
const char kChromeUIHistoryHost[] = "history";
const char kChromeUIInspectHost[] = "inspect";
const char kChromeUIIntersitialsHost[] = "interstitials";
const char kChromeUINetExportHost[] = "net-export";
const char kChromeUINewTabHost[] = "newtab";
const char kChromeUINTPTilesInternalsHost[] = "ntp-tiles-internals";
......
......@@ -16,6 +16,7 @@ extern const char kChromeUICreditsURL[];
extern const char kChromeUIFlagsURL[];
extern const char kChromeUIHistoryURL[];
extern const char kChromeUIInspectURL[];
extern const char kChromeUIIntersitialsURL[];
extern const char kChromeUINewTabURL[];
extern const char kChromeUINTPTilesInternalsURL[];
extern const char kChromeUIOfflineURL[];
......@@ -39,6 +40,7 @@ extern const char kChromeUIGCMInternalsHost[];
extern const char kChromeUIHistogramHost[];
extern const char kChromeUIHistoryHost[];
extern const char kChromeUIInspectHost[];
extern const char kChromeUIIntersitialsHost[];
extern const char kChromeUINetExportHost[];
extern const char kChromeUINewTabHost[];
extern const char kChromeUINTPTilesInternalsHost[];
......
......@@ -108,6 +108,7 @@ source_set("webui_internal") {
"//ios/chrome/browser/signin",
"//ios/chrome/browser/sync",
"//ios/chrome/browser/ui/webui/gcm",
"//ios/chrome/browser/ui/webui/interstitials",
"//ios/chrome/browser/ui/webui/net_export",
"//ios/chrome/browser/ui/webui/policy",
"//ios/chrome/browser/ui/webui/translate_internals",
......
......@@ -18,6 +18,7 @@
#include "ios/chrome/browser/ui/webui/flags_ui.h"
#include "ios/chrome/browser/ui/webui/gcm/gcm_internals_ui.h"
#include "ios/chrome/browser/ui/webui/inspect/inspect_ui.h"
#include "ios/chrome/browser/ui/webui/interstitials/interstitial_ui.h"
#include "ios/chrome/browser/ui/webui/net_export/net_export_ui.h"
#include "ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
#include "ios/chrome/browser/ui/webui/omaha_ui.h"
......@@ -85,6 +86,8 @@ WebUIIOSFactoryFunction GetWebUIIOSFactoryFunction(const GURL& url) {
return &NewWebUIIOS<GCMInternalsUI>;
if (url_host == kChromeUIInspectHost)
return &NewWebUIIOS<InspectUI>;
if (url_host == kChromeUIIntersitialsHost)
return &NewWebUIIOS<InterstitialUI>;
if (url_host == kChromeUINetExportHost)
return &NewWebUIIOS<NetExportUI>;
if (url_host == kChromeUINTPTilesInternalsHost)
......
# 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.
source_set("interstitials") {
public = [ "interstitial_ui.h" ]
sources = [
"interstitial_ui.mm",
"interstitial_ui_util.h",
"interstitial_ui_util.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
":constants",
"//base",
"//components/resources",
"//components/security_interstitials/core",
"//ios/chrome/browser:chrome_url_constants",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/ssl",
"//ios/web/public/security",
"//ios/web/public/webui",
"//net",
"//ui/base",
"//url",
]
}
source_set("constants") {
sources = [
"interstitial_ui_constants.h",
"interstitial_ui_constants.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
source_set("eg_tests") {
configs += [ "//build/config/compiler:enable_arc" ]
defines = [ "CHROME_EARL_GREY_1" ]
testonly = true
sources = [ "interstitial_ui_egtest.mm" ]
deps = [
":constants",
"//base",
"//base/test:test_support",
"//ios/chrome/browser:chrome_url_constants",
"//ios/chrome/test/app:test_support",
"//ios/chrome/test/earl_grey:test_support",
"//ios/testing/earl_grey:earl_grey_support",
"//net:test_support",
"//ui/base",
]
libs = [ "XCTest.framework" ]
}
source_set("eg2_tests") {
defines = [ "CHROME_EARL_GREY_2" ]
configs += [
"//build/config/compiler:enable_arc",
"//build/config/ios:xctest_config",
]
testonly = true
sources = [ "interstitial_ui_egtest.mm" ]
deps = [
":constants",
"//base",
"//base/test:test_support",
"//ios/chrome/browser:chrome_url_constants",
"//ios/chrome/test/earl_grey:eg_test_support+eg2",
"//ios/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib",
"//ios/web/public/test:element_selector",
"//net:test_support",
"//ui/base",
]
libs = [ "UIKit.framework" ]
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_H_
#define IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_H_
#include "ios/web/public/webui/web_ui_ios_controller.h"
// The WebUI handler for chrome://interstitials.
class InterstitialUI : public web::WebUIIOSController {
public:
explicit InterstitialUI(web::WebUIIOS* web_ui);
~InterstitialUI() override;
InterstitialUI(InterstitialUI&& other) = default;
InterstitialUI& operator=(InterstitialUI&& other) = default;
};
#endif // IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_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/chrome/browser/ui/webui/interstitials/interstitial_ui.h"
#import <Foundation/Foundation.h>
#include <memory>
#include <utility>
#include "base/memory/ref_counted_memory.h"
#include "base/time/time.h"
#include "components/grit/dev_ui_components_resources.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_constants.h"
#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_util.h"
#import "ios/web/public/security/web_interstitial_delegate.h"
#import "ios/web/public/web_state.h"
#include "ios/web/public/webui/url_data_source_ios.h"
#include "ios/web/public/webui/web_ui_ios.h"
#include "ios/web/public/webui/web_ui_ios_data_source.h"
#include "net/base/url_util.h"
#include "ui/base/resource/resource_bundle.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Implementation of chrome://interstitials demonstration pages.
class InterstitialHTMLSource : public web::URLDataSourceIOS {
public:
explicit InterstitialHTMLSource(ChromeBrowserState* browser_state);
~InterstitialHTMLSource() override;
InterstitialHTMLSource(InterstitialHTMLSource&& other) = default;
InterstitialHTMLSource& operator=(InterstitialHTMLSource&& other) = default;
private:
// web::URLDataSourceIOS:
std::string GetSource() const override;
void StartDataRequest(
const std::string& path,
web::URLDataSourceIOS::GotDataCallback callback) override;
std::string GetMimeType(const std::string& path) const override;
// The ChromeBrowserState passed on initialization. Used to construct
// WebStates that are passed to WebInterstitialDelegates.
ChromeBrowserState* browser_state_ = nullptr;
};
} // namespace
#pragma mark - InterstitialHTMLSource
InterstitialHTMLSource::InterstitialHTMLSource(
ChromeBrowserState* browser_state)
: browser_state_(browser_state) {
DCHECK(browser_state_);
}
InterstitialHTMLSource::~InterstitialHTMLSource() = default;
std::string InterstitialHTMLSource::GetMimeType(
const std::string& mime_type) const {
return "text/html";
}
std::string InterstitialHTMLSource::GetSource() const {
return kChromeUIIntersitialsHost;
}
void InterstitialHTMLSource::StartDataRequest(
const std::string& path,
web::URLDataSourceIOS::GotDataCallback callback) {
std::unique_ptr<web::WebState> web_state =
web::WebState::Create(web::WebState::CreateParams(browser_state_));
std::unique_ptr<web::WebInterstitialDelegate> interstitial_delegate;
std::string html;
// Using this form of the path so we can do exact matching, while ignoring the
// query (everything after the ? character).
GURL url = GURL(kChromeUIIntersitialsURL).GetWithEmptyPath().Resolve(path);
std::string path_without_query = url.path();
if (path_without_query == kChromeInterstitialSslPath) {
interstitial_delegate = CreateSslBlockingPageDelegate(web_state.get(), url);
} else if (path_without_query == kChromeInterstitialCaptivePortalPath) {
interstitial_delegate =
CreateCaptivePortalBlockingPageDelegate(web_state.get());
}
// TODO(crbug.com/1064805): Update the page HTML when a link for an
// unsupported interstitial type is tapped.
// Use the HTML generated from the interstitial delegate if created
// successfully. Otherwise, return the default chrome://interstitials HTML.
if (interstitial_delegate) {
html = interstitial_delegate->GetHtmlContents();
} else {
html = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
IDR_SECURITY_INTERSTITIAL_UI_HTML);
}
std::move(callback).Run(base::RefCountedString::TakeString(&html));
}
#pragma mark - InterstitialUI
InterstitialUI::InterstitialUI(web::WebUIIOS* web_ui)
: WebUIIOSController(web_ui) {
ChromeBrowserState* browser_state = ChromeBrowserState::FromWebUIIOS(web_ui);
web::URLDataSourceIOS::Add(browser_state,
new InterstitialHTMLSource(browser_state));
}
InterstitialUI::~InterstitialUI() = default;
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_CONSTANTS_H_
#define IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_CONSTANTS_H_
// Paths used by chrome://interstitials.
extern const char kChromeInterstitialSslPath[];
extern const char kChromeInterstitialCaptivePortalPath[];
// Query keys and values for chrome://interstitials/ssl
extern const char kChromeInterstitialSslUrlQueryKey[];
extern const char kChromeInterstitialSslOverridableQueryKey[];
extern const char kChromeInterstitialSslStrictEnforcementQueryKey[];
extern const char kChromeInterstitialSslTypeQueryKey[];
extern const char kChromeInterstitialSslTypeHpkpFailureQueryValue[];
extern const char kChromeInterstitialSslTypeCtFailureQueryValue[];
#endif // IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_CONSTANTS_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/chrome/browser/ui/webui/interstitials/interstitial_ui_constants.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
const char kChromeInterstitialSslPath[] = "/ssl";
const char kChromeInterstitialCaptivePortalPath[] = "/captiveportal";
const char kChromeInterstitialSslUrlQueryKey[] = "url";
const char kChromeInterstitialSslOverridableQueryKey[] = "overridable";
const char kChromeInterstitialSslStrictEnforcementQueryKey[] =
"strict_enforcement";
const char kChromeInterstitialSslTypeQueryKey[] = "type";
const char kChromeInterstitialSslTypeHpkpFailureQueryValue[] = "hpkp_failure";
const char kChromeInterstitialSslTypeCtFailureQueryValue[] = "ct_failure";
// 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 <XCTest/XCTest.h>
#include "ios/chrome/browser/chrome_url_constants.h"
#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_constants.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Test case for chrome://interstitials WebUI page.
@interface InterstitialWebUITestCase : ChromeTestCase
@end
@implementation InterstitialWebUITestCase
// Tests that chrome://interstitials loads correctly.
- (void)testLoadInterstitialUI {
[ChromeEarlGrey loadURL:GURL(kChromeUIIntersitialsURL)];
[ChromeEarlGrey waitForWebStateContainingText:"Choose an interstitial"];
}
// Tests that chrome://interstitials/ssl loads correctly.
- (void)testLoadSSLInterstitialUI {
GURL SSLInterstitialURL =
GURL(kChromeUIIntersitialsURL).Resolve(kChromeInterstitialSslPath);
[ChromeEarlGrey loadURL:SSLInterstitialURL];
[ChromeEarlGrey
waitForWebStateContainingText:"Your connection is not private"];
}
// Tests that chrome://interstitials/captiveportal loads correctly.
- (void)testLoadCaptivePortalInterstitialUI {
GURL captivePortalInterstitialURL =
GURL(kChromeUIIntersitialsURL)
.Resolve(kChromeInterstitialCaptivePortalPath);
[ChromeEarlGrey loadURL:captivePortalInterstitialURL];
[ChromeEarlGrey waitForWebStateContainingText:"Connect to Wi-Fi"];
}
@end
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_UTIL_H_
#define IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_UTIL_H_
#include <memory>
class GURL;
namespace web {
class WebInterstitialDelegate;
class WebState;
} // namespace web
// Creates an interstitial delegate for chrome://interstitials/ssl.
std::unique_ptr<web::WebInterstitialDelegate> CreateSslBlockingPageDelegate(
web::WebState* web_state,
const GURL& url);
// Creates an interstitial delegate for chrome://interstitials/captiveportal.
std::unique_ptr<web::WebInterstitialDelegate>
CreateCaptivePortalBlockingPageDelegate(web::WebState* web_state);
#endif // IOS_CHROME_BROWSER_UI_WEBUI_INTERSTITIALS_INTERSTITIAL_UI_UTIL_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/chrome/browser/ui/webui/interstitials/interstitial_ui_util.h"
#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/time/time.h"
#include "components/grit/dev_ui_components_resources.h"
#include "components/security_interstitials/core/ssl_error_options_mask.h"
#include "crypto/rsa_private_key.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#include "ios/chrome/browser/ssl/ios_captive_portal_blocking_page.h"
#include "ios/chrome/browser/ssl/ios_ssl_blocking_page.h"
#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_constants.h"
#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_util.h"
#import "ios/web/public/security/web_interstitial_delegate.h"
#include "ios/web/public/webui/url_data_source_ios.h"
#include "ios/web/public/webui/web_ui_ios.h"
#include "ios/web/public/webui/web_ui_ios_data_source.h"
#include "net/base/url_util.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
scoped_refptr<net::X509Certificate> CreateFakeCert() {
// NSS requires that serial numbers be unique even for the same issuer;
// as all fake certificates will contain the same issuer name, it's
// necessary to ensure the serial number is unique, as otherwise
// NSS will fail to parse.
static base::AtomicSequenceNumber serial_number;
std::unique_ptr<crypto::RSAPrivateKey> unused_key;
std::string cert_der;
if (!net::x509_util::CreateKeyAndSelfSignedCert(
"CN=Error", static_cast<uint32_t>(serial_number.GetNext()),
base::Time::Now() - base::TimeDelta::FromMinutes(5),
base::Time::Now() + base::TimeDelta::FromMinutes(5), &unused_key,
&cert_der)) {
return nullptr;
}
return net::X509Certificate::CreateFromBytes(cert_der.data(),
cert_der.size());
}
}
std::unique_ptr<web::WebInterstitialDelegate> CreateSslBlockingPageDelegate(
web::WebState* web_state,
const GURL& url) {
DCHECK_EQ(kChromeInterstitialSslPath, url.path());
// Fake parameters for SSL blocking page.
GURL request_url("https://example.com");
std::string url_param;
if (net::GetValueForKeyInQuery(url, kChromeInterstitialSslUrlQueryKey,
&url_param)) {
GURL query_url_param(url_param);
if (query_url_param.is_valid())
request_url = query_url_param;
}
bool overridable = false;
std::string overridable_param;
if (net::GetValueForKeyInQuery(url, kChromeInterstitialSslOverridableQueryKey,
&overridable_param)) {
overridable = overridable_param == "1";
}
bool strict_enforcement = false;
std::string strict_enforcement_param;
if (net::GetValueForKeyInQuery(
url, kChromeInterstitialSslStrictEnforcementQueryKey,
&strict_enforcement_param)) {
strict_enforcement = strict_enforcement_param == "1";
}
int cert_error = net::ERR_CERT_CONTAINS_ERRORS;
std::string type_param;
if (net::GetValueForKeyInQuery(url, kChromeInterstitialSslTypeQueryKey,
&type_param)) {
if (type_param == kChromeInterstitialSslTypeHpkpFailureQueryValue) {
cert_error = net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
} else if (type_param == kChromeInterstitialSslTypeCtFailureQueryValue) {
cert_error = net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
}
}
net::SSLInfo ssl_info;
ssl_info.cert = ssl_info.unverified_cert = CreateFakeCert();
int options_mask = 0;
if (overridable) {
options_mask |=
security_interstitials::SSLErrorOptionsMask::SOFT_OVERRIDE_ENABLED;
}
if (strict_enforcement) {
options_mask |=
security_interstitials::SSLErrorOptionsMask::STRICT_ENFORCEMENT;
}
return std::make_unique<IOSSSLBlockingPage>(
web_state, cert_error, ssl_info, request_url, options_mask,
base::Time::NowFromSystemTime(), base::OnceCallback<void(bool)>());
}
std::unique_ptr<web::WebInterstitialDelegate>
CreateCaptivePortalBlockingPageDelegate(web::WebState* web_state) {
GURL landing_url("https://captive.portal/login");
GURL request_url("https://google.com");
return std::make_unique<IOSCaptivePortalBlockingPage>(
web_state, request_url, landing_url, base::OnceCallback<void(bool)>());
}
......@@ -108,6 +108,7 @@ chrome_ios_eg_test("ios_chrome_ui_egtests") {
"//ios/chrome/browser/ui/tabs:eg_tests",
"//ios/chrome/browser/ui/toolbar:eg_tests",
"//ios/chrome/browser/ui/webui:eg_tests",
"//ios/chrome/browser/ui/webui/interstitials:eg_tests",
]
shards = 2
......
......@@ -129,6 +129,7 @@ chrome_ios_eg2_test("ios_chrome_ui_eg2tests_module") {
"//ios/chrome/browser/ui/tabs:eg2_tests",
"//ios/chrome/browser/ui/toolbar:eg2_tests",
"//ios/chrome/browser/ui/webui:eg2_tests",
"//ios/chrome/browser/ui/webui/interstitials:eg2_tests",
]
data_deps = [ ":ios_chrome_eg2tests" ]
......
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