1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/interstitials/interstitial_ui.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
12 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
13 #include "chrome/browser/ssl/bad_clock_blocking_page.h"
14 #include "chrome/browser/ssl/ssl_blocking_page.h"
15 #include "chrome/common/url_constants.h"
16 #include "chrome/grit/browser_resources.h"
17 #include "components/grit/components_resources.h"
18 #include "content/public/browser/interstitial_page_delegate.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_ui.h"
21 #include "content/public/browser/web_ui_controller.h"
22 #include "content/public/browser/web_ui_data_source.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/url_util.h"
25 #include "net/cert/x509_certificate.h"
26 #include "net/ssl/ssl_info.h"
27 #include "ui/base/resource/resource_bundle.h"
29 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
30 #include "chrome/browser/ssl/captive_portal_blocking_page.h"
35 class InterstitialHTMLSource
: public content::URLDataSource
{
37 explicit InterstitialHTMLSource(content::WebContents
* web_contents
);
38 ~InterstitialHTMLSource() override
;
40 // content::URLDataSource:
41 std::string
GetMimeType(const std::string
& mime_type
) const override
;
42 std::string
GetSource() const override
;
43 bool ShouldAddContentSecurityPolicy() const override
;
44 void StartDataRequest(
45 const std::string
& path
,
46 int render_process_id
,
48 const content::URLDataSource::GotDataCallback
& callback
) override
;
51 content::WebContents
* web_contents_
;
52 DISALLOW_COPY_AND_ASSIGN(InterstitialHTMLSource
);
55 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
56 // Provides fake connection information to the captive portal blocking page so
57 // that both Wi-Fi and non Wi-Fi blocking pages can be displayed.
58 class CaptivePortalBlockingPageWithNetInfo
: public CaptivePortalBlockingPage
{
60 CaptivePortalBlockingPageWithNetInfo(
61 content::WebContents
* web_contents
,
62 const GURL
& request_url
,
63 const GURL
& login_url
,
64 const net::SSLInfo
& ssl_info
,
65 const base::Callback
<void(bool)>& callback
,
67 const std::string
& wifi_ssid
)
68 : CaptivePortalBlockingPage(web_contents
,
75 wifi_ssid_(wifi_ssid
) {}
78 // CaptivePortalBlockingPage methods:
79 bool IsWifiConnection() const override
{ return is_wifi_
; }
80 std::string
GetWiFiSSID() const override
{ return wifi_ssid_
; }
83 const std::string wifi_ssid_
;
85 DISALLOW_COPY_AND_ASSIGN(CaptivePortalBlockingPageWithNetInfo
);
89 SSLBlockingPage
* CreateSSLBlockingPage(content::WebContents
* web_contents
) {
90 // Random parameters for SSL blocking page.
91 int cert_error
= net::ERR_CERT_CONTAINS_ERRORS
;
92 GURL
request_url("https://example.com");
93 bool overridable
= false;
94 bool strict_enforcement
= false;
95 base::Time time_triggered_
= base::Time::NowFromSystemTime();
96 std::string url_param
;
97 if (net::GetValueForKeyInQuery(web_contents
->GetURL(),
100 if (GURL(url_param
).is_valid())
101 request_url
= GURL(url_param
);
103 std::string overridable_param
;
104 if (net::GetValueForKeyInQuery(web_contents
->GetURL(),
106 &overridable_param
)) {
107 overridable
= overridable_param
== "1";
109 std::string strict_enforcement_param
;
110 if (net::GetValueForKeyInQuery(web_contents
->GetURL(),
111 "strict_enforcement",
112 &strict_enforcement_param
)) {
113 strict_enforcement
= strict_enforcement_param
== "1";
115 net::SSLInfo ssl_info
;
116 ssl_info
.cert
= new net::X509Certificate(
117 request_url
.host(), "CA", base::Time::Max(), base::Time::Max());
118 // This delegate doesn't create an interstitial.
119 int options_mask
= 0;
121 options_mask
|= SSLBlockingPage::OVERRIDABLE
;
122 if (strict_enforcement
)
123 options_mask
|= SSLBlockingPage::STRICT_ENFORCEMENT
;
124 return new SSLBlockingPage(web_contents
, cert_error
, ssl_info
, request_url
,
125 options_mask
, time_triggered_
, nullptr,
126 base::Callback
<void(bool)>());
129 BadClockBlockingPage
* CreateBadClockBlockingPage(
130 content::WebContents
* web_contents
) {
131 // Set up a fake clock error.
132 int cert_error
= net::ERR_CERT_DATE_INVALID
;
133 GURL
request_url("https://example.com");
134 bool overridable
= false;
135 bool strict_enforcement
= false;
136 std::string url_param
;
137 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "url", &url_param
) &&
138 GURL(url_param
).is_valid()) {
139 request_url
= GURL(url_param
);
141 std::string overridable_param
;
142 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "overridable",
143 &overridable_param
)) {
144 overridable
= overridable_param
== "1";
146 std::string strict_enforcement_param
;
147 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "strict_enforcement",
148 &strict_enforcement_param
)) {
149 strict_enforcement
= strict_enforcement_param
== "1";
152 // Determine whether to change the clock to be ahead or behind.
153 base::Time time_triggered_
= base::Time::NowFromSystemTime();
154 std::string clock_manipulation_param
;
155 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "clock_manipulation",
156 &clock_manipulation_param
)) {
158 if (!base::StringToInt(clock_manipulation_param
, &time_offset
))
160 time_triggered_
+= base::TimeDelta::FromDays(365 * time_offset
);
163 net::SSLInfo ssl_info
;
164 ssl_info
.cert
= new net::X509Certificate(
165 request_url
.host(), "CA", base::Time::Max(), base::Time::Max());
166 // This delegate doesn't create an interstitial.
167 int options_mask
= 0;
169 options_mask
|= SSLBlockingPage::OVERRIDABLE
;
170 if (strict_enforcement
)
171 options_mask
|= SSLBlockingPage::STRICT_ENFORCEMENT
;
172 return new BadClockBlockingPage(web_contents
, cert_error
, ssl_info
,
173 request_url
, time_triggered_
,
174 base::Callback
<void(bool)>());
177 SafeBrowsingBlockingPage
* CreateSafeBrowsingBlockingPage(
178 content::WebContents
* web_contents
) {
179 SBThreatType threat_type
= SB_THREAT_TYPE_URL_MALWARE
;
180 GURL
request_url("http://example.com");
181 std::string url_param
;
182 if (net::GetValueForKeyInQuery(web_contents
->GetURL(),
185 if (GURL(url_param
).is_valid())
186 request_url
= GURL(url_param
);
188 std::string type_param
;
189 if (net::GetValueForKeyInQuery(web_contents
->GetURL(),
192 if (type_param
== "malware") {
193 threat_type
= SB_THREAT_TYPE_URL_MALWARE
;
194 } else if (type_param
== "phishing") {
195 threat_type
= SB_THREAT_TYPE_URL_PHISHING
;
196 } else if (type_param
== "clientside_malware") {
197 threat_type
= SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL
;
198 } else if (type_param
== "clientside_phishing") {
199 threat_type
= SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
;
200 // Interstitials for client side phishing urls load after the page loads
201 // (see SafeBrowsingBlockingPage::IsMainPageLoadBlocked), so there should
202 // either be a new navigation entry, or there shouldn't be any pending
203 // entries. Clear any pending navigation entries.
204 content::NavigationController
* controller
=
205 &web_contents
->GetController();
206 controller
->DiscardNonCommittedEntries();
209 SafeBrowsingBlockingPage::UnsafeResource resource
;
210 resource
.url
= request_url
;
211 resource
.threat_type
= threat_type
;
212 // Create a blocking page without showing the interstitial.
213 return SafeBrowsingBlockingPage::CreateBlockingPage(
214 g_browser_process
->safe_browsing_service()->ui_manager().get(),
219 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
220 CaptivePortalBlockingPage
* CreateCaptivePortalBlockingPage(
221 content::WebContents
* web_contents
) {
222 bool is_wifi_connection
= false;
223 GURL
landing_url("https://captive.portal/login");
224 GURL
request_url("https://google.com");
225 // Not initialized to a default value, since non-empty wifi_ssid is
226 // considered a wifi connection, even if is_wifi_connection is false.
227 std::string wifi_ssid
;
229 std::string request_url_param
;
230 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "url",
231 &request_url_param
)) {
232 if (GURL(request_url_param
).is_valid())
233 request_url
= GURL(request_url_param
);
235 std::string landing_url_param
;
236 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "landing_page",
237 &landing_url_param
)) {
238 if (GURL(landing_url_param
).is_valid())
239 landing_url
= GURL(landing_url_param
);
241 std::string wifi_connection_param
;
242 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "is_wifi",
243 &wifi_connection_param
)) {
244 is_wifi_connection
= wifi_connection_param
== "1";
246 std::string wifi_ssid_param
;
247 if (net::GetValueForKeyInQuery(web_contents
->GetURL(), "wifi_name",
249 wifi_ssid
= wifi_ssid_param
;
251 net::SSLInfo ssl_info
;
252 ssl_info
.cert
= new net::X509Certificate(
253 request_url
.host(), "CA", base::Time::Max(), base::Time::Max());
254 CaptivePortalBlockingPage
* blocking_page
=
255 new CaptivePortalBlockingPageWithNetInfo(
256 web_contents
, request_url
, landing_url
, ssl_info
,
257 base::Callback
<void(bool)>(), is_wifi_connection
, wifi_ssid
);
258 return blocking_page
;
264 InterstitialUI::InterstitialUI(content::WebUI
* web_ui
)
265 : WebUIController(web_ui
) {
266 scoped_ptr
<InterstitialHTMLSource
> html_source(
267 new InterstitialHTMLSource(web_ui
->GetWebContents()));
268 Profile
* profile
= Profile::FromWebUI(web_ui
);
269 content::URLDataSource::Add(profile
, html_source
.release());
272 InterstitialUI::~InterstitialUI() {
275 // InterstitialHTMLSource
277 InterstitialHTMLSource::InterstitialHTMLSource(
278 content::WebContents
* web_contents
)
279 : web_contents_(web_contents
) {
282 InterstitialHTMLSource::~InterstitialHTMLSource() {
285 std::string
InterstitialHTMLSource::GetMimeType(
286 const std::string
& mime_type
) const {
290 std::string
InterstitialHTMLSource::GetSource() const {
291 return chrome::kChromeUIInterstitialHost
;
294 bool InterstitialHTMLSource::ShouldAddContentSecurityPolicy()
299 void InterstitialHTMLSource::StartDataRequest(
300 const std::string
& path
,
301 int render_process_id
,
303 const content::URLDataSource::GotDataCallback
& callback
) {
304 scoped_ptr
<content::InterstitialPageDelegate
> interstitial_delegate
;
305 if (base::StartsWith(path
, "ssl", base::CompareCase::SENSITIVE
)) {
306 interstitial_delegate
.reset(CreateSSLBlockingPage(web_contents_
));
307 } else if (base::StartsWith(path
, "safebrowsing",
308 base::CompareCase::SENSITIVE
)) {
309 interstitial_delegate
.reset(CreateSafeBrowsingBlockingPage(web_contents_
));
310 } else if (base::StartsWith(path
, "clock", base::CompareCase::SENSITIVE
)) {
311 interstitial_delegate
.reset(CreateBadClockBlockingPage(web_contents_
));
313 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
314 else if (base::StartsWith(path
, "captiveportal",
315 base::CompareCase::SENSITIVE
))
317 interstitial_delegate
.reset(CreateCaptivePortalBlockingPage(web_contents_
));
321 if (interstitial_delegate
.get()) {
322 html
= interstitial_delegate
.get()->GetHTMLContents();
324 html
= ResourceBundle::GetSharedInstance()
325 .GetRawDataResource(IDR_SECURITY_INTERSTITIAL_UI_HTML
)
328 scoped_refptr
<base::RefCountedString
> html_bytes
= new base::RefCountedString
;
329 html_bytes
->data().assign(html
.begin(), html
.end());
330 callback
.Run(html_bytes
.get());