LEFT | RIGHT |
1 /* | 1 /* |
2 * Copyright (C) 2018 Google Inc. All rights reserved. | 2 * Copyright (C) 2018 Google LLC. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 * THE POSSIBILITY OF SUCH DAMAGE. | 23 * THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #import "config.h" | 26 #import "config.h" |
27 #import "SafeBrowsingController.h" | 27 #import "SafeBrowsingController.h" |
28 | 28 |
29 #if WK_API_ENABLED | 29 #if WK_API_ENABLED |
30 | 30 |
31 #import "APINavigationAction.h" | 31 #import "APINavigationAction.h" |
| 32 #import "SafeBrowsingContextProvider.h" |
32 #import "SafeBrowsingSPI.h" | 33 #import "SafeBrowsingSPI.h" |
33 #import "WKWebView.h" | 34 #import "WKNavigationActionInternal.h" |
| 35 #import "WKPreferences.h" |
| 36 #import "WKWebViewConfiguration.h" |
| 37 #import "WKWebViewInternal.h" |
34 #import "WebFramePolicyListenerProxy.h" | 38 #import "WebFramePolicyListenerProxy.h" |
35 #import "WebPageProxy.h" | 39 #import "WebPageProxy.h" |
36 | 40 |
37 namespace WebKit { | 41 namespace WebKit { |
38 | 42 |
39 const char* SafeBrowsingController::s_warningPageUrl = "file:///SafeBrowsing"; | 43 const char* SafeBrowsingController::s_warningPageUrl = "file:///SafeBrowsing"; |
40 | 44 |
41 SafeBrowsingController::SafeBrowsingController(WKWebView *webView) | 45 SafeBrowsingController::SafeBrowsingController(WKWebView *webView) |
42 : m_webView(webView) | 46 : m_webView(webView) |
43 { | 47 { |
44 } | 48 } |
45 | 49 |
46 SafeBrowsingController::~SafeBrowsingController() | 50 SafeBrowsingController::~SafeBrowsingController() |
47 { | 51 { |
48 // FIXME: Deal with getting destroyed while callbacks are still outstanding. | |
49 // Possibly need to use reference-counting on something that the lambda has | |
50 // access to, so it knows not to call into destroyed objects. | |
51 } | 52 } |
52 | 53 |
53 void SafeBrowsingController::checkURL(Ref<API::NavigationAction>&& navigationAct
ion, NavigationPolicyDecider&& policyDecider, Ref<WebFramePolicyListenerProxy>&&
listener) | 54 void SafeBrowsingController::checkURL(Ref<API::NavigationAction>&& navigationAct
ion, NavigationPolicyDecider&& policyDecider, Ref<WebFramePolicyListenerProxy>&&
listener) |
54 { | 55 { |
55 auto url = navigationAction->originalURL(); | 56 bool shouldSkipSafeBrowsingLookUp = !m_webView.configuration.preferences.saf
eBrowsingEnabled; |
56 auto safeBrowsingCheck = std::make_unique<SafeBrowsingCheck>(WTFMove(listene
r), url); | 57 if (!shouldSkipSafeBrowsingLookUp) { |
| 58 bool warningBypassed = navigationAction->navigationType() == WebCore::Na
vigationType::LinkClicked |
| 59 && navigationAction->sourceFrame() |
| 60 && navigationAction->sourceFrame()->page()->pageLoadState().url() ==
s_warningPageUrl |
| 61 && navigationAction->sourceFrame()->page()->currentURL() == navigati
onAction->originalURL().string(); |
| 62 |
| 63 if (warningBypassed) |
| 64 m_warningIgnoredUrls.add(navigationAction->originalURL()); |
| 65 |
| 66 shouldSkipSafeBrowsingLookUp = warningBypassed || m_warningIgnoredUrls.c
ontains(navigationAction->originalURL()); |
| 67 } |
| 68 |
| 69 auto safeBrowsingCheck = std::make_unique<SafeBrowsingCheck>(WTFMove(listene
r), WTFMove(navigationAction)); |
57 auto checkRaw = safeBrowsingCheck.get(); | 70 auto checkRaw = safeBrowsingCheck.get(); |
58 m_checks.add(WTFMove(safeBrowsingCheck)); | 71 m_checks.add(WTFMove(safeBrowsingCheck)); |
59 | 72 |
60 auto policyCompletionHandler = [checkRaw, this] (WKNavigationActionPolicy po
licy, std::optional<WebsitePoliciesData>&& data) mutable { | 73 if (shouldSkipSafeBrowsingLookUp) |
61 receivedNavigationPolicyDecision(*checkRaw, policy, WTFMove(data)); | 74 receivedSafeBrowsingResult(checkRaw, SafeBrowsingResult::Safe); |
| 75 else { |
| 76 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IO
S) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) |
| 77 auto weakThis = m_weakPtrFactory.createWeakPtr(*this); |
| 78 [SafeBrowsingContextProvider::sharedLookupContext() lookUpURL:checkRaw->
navigationAction->request().url() completionHandler:^(SSBLookupResult* result, N
SError* error) { |
| 79 if (!weakThis) |
| 80 return; |
| 81 |
| 82 SafeBrowsingResult safeBrowsingResult = SafeBrowsingResult::Safe; |
| 83 if (result.serviceLookupResults) { |
| 84 for (SSBServiceLookupResult* details in result.serviceLookupResu
lts) { |
| 85 // FIXME: Keep track of the different types in order to give
different warnings. |
| 86 if (details.isPhishing || details.isMalware || details.isUnw
antedSoftware || details.isKnownToBeUnsafe) |
| 87 safeBrowsingResult = SafeBrowsingResult::Unsafe; |
| 88 } |
| 89 } |
| 90 weakThis->receivedSafeBrowsingResult(checkRaw, safeBrowsingResult); |
| 91 }]; |
| 92 #else |
| 93 receivedSafeBrowsingResult(checkRaw, SafeBrowsingResult::Safe); |
| 94 #endif |
| 95 } |
| 96 |
| 97 auto policyCompletionHandler = [checkRaw, weakThis = m_weakPtrFactory.create
WeakPtr(*this)] (WKNavigationActionPolicy policy, std::optional<WebsitePoliciesD
ata>&& data) mutable { |
| 98 if (weakThis) |
| 99 weakThis->receivedNavigationPolicyDecision(*checkRaw, policy, WTFMov
e(data)); |
62 }; | 100 }; |
63 | 101 |
64 policyDecider(WTFMove(policyCompletionHandler)); | 102 policyDecider(WTFMove(policyCompletionHandler)); |
65 | |
66 if (navigationAction->navigationType() == WebCore::NavigationType::LinkClick
ed | |
67 && navigationAction->sourceFrame() | |
68 && navigationAction->sourceFrame()->page()->pageLoadState().url() == s_w
arningPageUrl | |
69 && navigationAction->sourceFrame()->page()->currentURL() == navigationAc
tion->originalURL().string()) { | |
70 receivedSafeBrowsingDecision(checkRaw, false); | |
71 return; | |
72 } | |
73 | |
74 // Creating a raw pointer is a bit unusual, but matches what's done in tryAp
pLink. | |
75 // FIXME: Make the function be owned by SafeBrowsingController? It'll pretty
much | |
76 // amount to the same thing logically, but might be cleaner. | |
77 // Or maybe this really needs to be a WeakPtr? So that we get it nulled out
for | |
78 // free. | |
79 auto* safeBrowsingCompletionHandler = new WTF::Function<void(SSBLookupResult
*, NSError*)>([checkRaw, this](SSBLookupResult* result, NSError* error) mutable
{ | |
80 if (error) | |
81 WTFLogAlways("Error doing SafeBrowsing check"); | |
82 bool isUnsafe = false; | |
83 if (result.serviceLookupResults) { | |
84 for (SSBServiceLookupResult* details in result.serviceLookupResults)
{ | |
85 // FIXME: Do we want to keep track of the different types in ord
er to give | |
86 // different warnings? | |
87 if (details.isPhishing || details.isMalware || details.isUnwante
dSoftware || details.isKnownToBeUnsafe) | |
88 isUnsafe = true; | |
89 } | |
90 } | |
91 receivedSafeBrowsingDecision(checkRaw, isUnsafe); | |
92 }); | |
93 | |
94 [[SSBLookupContext sharedLookupContext] lookUpURL:url completionHandler:[saf
eBrowsingCompletionHandler](SSBLookupResult* result, NSError* error){ | |
95 (*safeBrowsingCompletionHandler)(result, error); | |
96 delete safeBrowsingCompletionHandler; | |
97 }]; | |
98 } | |
99 | |
100 void SafeBrowsingController::placeholder() | |
101 { | |
102 [m_webView goBack]; | |
103 } | 103 } |
104 | 104 |
105 void SafeBrowsingController::receivedNavigationPolicyDecision(SafeBrowsingContro
ller::SafeBrowsingCheck& check, WKNavigationActionPolicy policy, std::optional<W
ebsitePoliciesData>&& data) | 105 void SafeBrowsingController::receivedNavigationPolicyDecision(SafeBrowsingContro
ller::SafeBrowsingCheck& check, WKNavigationActionPolicy policy, std::optional<W
ebsitePoliciesData>&& data) |
106 { | 106 { |
107 check.navigationPolicyDecision = policy; | 107 check.navigationPolicyDecision = policy; |
108 check.websitePoliciesData = WTFMove(data); | 108 check.websitePoliciesData = WTFMove(data); |
109 maybeFinishedCheck(check); | 109 maybeFinishedCheck(check); |
110 } | 110 } |
111 | 111 |
112 void SafeBrowsingController::receivedSafeBrowsingDecision(SafeBrowsingCheck* che
ck, bool isUnsafe) | 112 void SafeBrowsingController::receivedSafeBrowsingResult(SafeBrowsingCheck* check
, SafeBrowsingResult safeBrowsingResult) |
113 { | 113 { |
114 if (!m_checks.contains(check)) | 114 if (!m_checks.contains(check)) |
115 return; | 115 return; |
116 | 116 |
117 check->safeBrowsingLookUpComplete = true; | 117 check->safeBrowsingResult = safeBrowsingResult; |
118 check->isUnsafe = isUnsafe; | |
119 maybeFinishedCheck(*check); | 118 maybeFinishedCheck(*check); |
120 } | 119 } |
121 | 120 |
122 void SafeBrowsingController::maybeFinishedCheck(SafeBrowsingController::SafeBrow
singCheck& check) | 121 void SafeBrowsingController::maybeFinishedCheck(SafeBrowsingController::SafeBrow
singCheck& check) |
123 { | 122 { |
124 if (!check.navigationPolicyDecision) | 123 if (!check.navigationPolicyDecision) |
125 return; | 124 return; |
126 | 125 |
127 if (check.navigationPolicyDecision.value() == WKNavigationActionPolicyAllow
&& !check.safeBrowsingLookUpComplete) | 126 if (check.navigationPolicyDecision.value() == WKNavigationActionPolicyAllow
&& !check.safeBrowsingResult) |
128 return; | 127 return; |
129 | 128 |
130 switch (check.navigationPolicyDecision.value()) { | 129 switch (check.navigationPolicyDecision.value()) { |
131 case WKNavigationActionPolicyAllow: | 130 case WKNavigationActionPolicyAllow: { |
132 if (check.isUnsafe) { | 131 if (check.safeBrowsingResult == SafeBrowsingResult::Safe) { |
133 check.listener->ignore(); | 132 check.listener->use(WTFMove(check.websitePoliciesData)); |
134 // FIXME: This really needs to be loaded in a way that permits local
ization. | 133 break; |
135 auto mainFrameUrl = m_webView.URL; | |
136 [m_webView _loadAlternateHTMLString:[NSString stringWithFormat:@"<st
yle>body { background-color: lightblue; }</style><body><h1>This is a simple Safe
Browsing warning.</h1><h2>You've been warned!!!</h2><h2><a href='%s'>Live danger
ously and visit the site anyway</a></h2>", mainFrameUrl.absoluteString.UTF8Strin
g] baseURL:WebCore::URL(WebCore::ParsedURLString, s_warningPageUrl) forUnreachab
leURL:mainFrameUrl]; | |
137 } else { | |
138 check.listener->use(std::move(check.websitePoliciesData)); | |
139 } | 134 } |
| 135 |
| 136 check.listener->ignore(); |
| 137 // FIXME: This really needs to be loaded in a way that permits localizat
ion. |
| 138 // FIXME: Make the warning message more similar to Safari, which means d
ifferent |
| 139 // wording depending on the type of warning (phishing, malware, etc.). |
| 140 auto targetMainFrameUrl = check.navigationAction->targetFrame()->isMainF
rame() ? check.navigationAction->request().url() : WebCore::URL(WebCore::ParsedU
RLString, check.navigationAction->targetFrame()->page()->currentURL()); |
| 141 NSString* warningString = [NSString stringWithFormat:@"<style>body { bac
kground-color: red; }</style><body><h1>This is a simple SafeBrowsing warning.</h
1><h2>You've been warned!!!</h2><h2><a id='visitAnyway' href='%s'>Visit the site
anyway</a></h2>", targetMainFrameUrl.string().utf8().data()]; |
| 142 [m_webView _loadAlternateHTMLString:warningString baseURL:WebCore::URL(W
ebCore::ParsedURLString, s_warningPageUrl) forUnreachableURL:targetMainFrameUrl]
; |
140 break; | 143 break; |
| 144 } |
141 case WKNavigationActionPolicyCancel: | 145 case WKNavigationActionPolicyCancel: |
142 check.listener->ignore(); | 146 check.listener->ignore(); |
143 break; | 147 break; |
144 case _WKNavigationActionPolicyDownload: | 148 case _WKNavigationActionPolicyDownload: |
145 check.listener->download(); | 149 check.listener->download(); |
146 break; | 150 break; |
147 default: | 151 default: |
148 ASSERT_NOT_REACHED(); | 152 ASSERT_NOT_REACHED(); |
149 } | 153 } |
150 m_checks.remove(&check); | 154 m_checks.remove(&check); |
151 } | 155 } |
152 | 156 |
153 } // namespace WebKit | 157 } // namespace WebKit |
154 | 158 |
155 #endif // WK_API_ENABLED | 159 #endif // WK_API_ENABLED |
LEFT | RIGHT |