LEFT | RIGHT |
1 /* | 1 /* |
2 * Copyright (C) 2018 Google LLC. 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 |
(...skipping 11 matching lines...) Expand all Loading... |
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 "WKNavigationActionInternal.h" | 34 #import "WKNavigationActionInternal.h" |
34 #import "WKPreferences.h" | 35 #import "WKPreferences.h" |
| 36 #import "WKWebViewConfiguration.h" |
35 #import "WKWebViewInternal.h" | 37 #import "WKWebViewInternal.h" |
36 #import "WKWebViewConfiguration.h" | |
37 #import "WebFramePolicyListenerProxy.h" | 38 #import "WebFramePolicyListenerProxy.h" |
38 #import "WebPageProxy.h" | 39 #import "WebPageProxy.h" |
39 | 40 |
40 namespace WebKit { | 41 namespace WebKit { |
41 | 42 |
42 const char* SafeBrowsingController::s_warningPageUrl = "file:///SafeBrowsing"; | 43 const char* SafeBrowsingController::s_warningPageUrl = "file:///SafeBrowsing"; |
43 | 44 |
44 SafeBrowsingController::SafeBrowsingController(WKWebView *webView) | 45 SafeBrowsingController::SafeBrowsingController(WKWebView *webView) |
45 : m_webView(webView) | 46 : m_webView(webView) |
46 { | 47 { |
47 } | 48 } |
48 | 49 |
49 SafeBrowsingController::~SafeBrowsingController() | 50 SafeBrowsingController::~SafeBrowsingController() |
50 { | 51 { |
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 bool shouldSkipSafeBrowsingLookUp = !m_webView.configuration.preferences.saf
eBrowsingEnabled; | 56 bool shouldSkipSafeBrowsingLookUp = !m_webView.configuration.preferences.saf
eBrowsingEnabled; |
56 if (!shouldSkipSafeBrowsingLookUp) { | 57 if (!shouldSkipSafeBrowsingLookUp) { |
57 bool warningBypassed = navigationAction->navigationType() == WebCore::Na
vigationType::LinkClicked | 58 bool warningBypassed = navigationAction->navigationType() == WebCore::Na
vigationType::LinkClicked |
58 && navigationAction->sourceFrame() | 59 && navigationAction->sourceFrame() |
59 && navigationAction->sourceFrame()->page()->pageLoadState().url() ==
s_warningPageUrl | 60 && navigationAction->sourceFrame()->page()->pageLoadState().url() ==
s_warningPageUrl |
60 && navigationAction->sourceFrame()->page()->currentURL() == navigati
onAction->originalURL().string(); | 61 && navigationAction->sourceFrame()->page()->currentURL() == navigati
onAction->originalURL().string(); |
61 | 62 |
62 // FIXME: Figure out the right persistence model? Right now, this persis
ts ignoring warnings for the currently | |
63 // displayed URL (i.e., the main-frame URL), but not for the specific su
bframe that triggered the | |
64 // warning. So the next attempt at loading that subframe will still trig
ger the warning. | |
65 // For subframes, the user might have no idea what URL is 'dangerous', s
o persisting that URL seems | |
66 // questionable. | |
67 // Another approach would be to exempt all loads triggered by the main-f
rame URL once the user | |
68 // bypasses a warning with that main-frame URL. But then we also need to
track what warning types | |
69 // the user has decided to bypass (e.g., maybe the user bypassed a phish
ing warning, but that | |
70 // shouldn't automatically imply they also want to bypass malware warnin
gs). | |
71 if (warningBypassed) | 63 if (warningBypassed) |
72 m_warningIgnoredUrls.add(navigationAction->originalURL()); | 64 m_warningIgnoredUrls.add(navigationAction->originalURL()); |
73 | 65 |
74 shouldSkipSafeBrowsingLookUp = warningBypassed || m_warningIgnoredUrls.c
ontains(navigationAction->originalURL()); | 66 shouldSkipSafeBrowsingLookUp = warningBypassed || m_warningIgnoredUrls.c
ontains(navigationAction->originalURL()); |
75 } | 67 } |
76 | 68 |
77 auto safeBrowsingCheck = std::make_unique<SafeBrowsingCheck>(WTFMove(listene
r), WTFMove(navigationAction)); | 69 auto safeBrowsingCheck = std::make_unique<SafeBrowsingCheck>(WTFMove(listene
r), WTFMove(navigationAction)); |
78 auto checkRaw = safeBrowsingCheck.get(); | 70 auto checkRaw = safeBrowsingCheck.get(); |
79 m_checks.add(WTFMove(safeBrowsingCheck)); | 71 m_checks.add(WTFMove(safeBrowsingCheck)); |
80 | 72 |
| 73 if (shouldSkipSafeBrowsingLookUp) |
| 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 |
81 auto policyCompletionHandler = [checkRaw, weakThis = m_weakPtrFactory.create
WeakPtr(*this)] (WKNavigationActionPolicy policy, std::optional<WebsitePoliciesD
ata>&& data) mutable { | 97 auto policyCompletionHandler = [checkRaw, weakThis = m_weakPtrFactory.create
WeakPtr(*this)] (WKNavigationActionPolicy policy, std::optional<WebsitePoliciesD
ata>&& data) mutable { |
82 if (weakThis) | 98 if (weakThis) |
83 weakThis->receivedNavigationPolicyDecision(*checkRaw, policy, WTFMov
e(data)); | 99 weakThis->receivedNavigationPolicyDecision(*checkRaw, policy, WTFMov
e(data)); |
84 }; | 100 }; |
85 | 101 |
86 policyDecider(WTFMove(policyCompletionHandler)); | 102 policyDecider(WTFMove(policyCompletionHandler)); |
87 | |
88 if (shouldSkipSafeBrowsingLookUp) { | |
89 receivedSafeBrowsingDecision(checkRaw, false); | |
90 return; | |
91 } | |
92 | |
93 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IO
S) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) | |
94 auto weakThis = m_weakPtrFactory.createWeakPtr(*this); | |
95 [[SSBLookupContext sharedLookupContext] lookUpURL:checkRaw->navigationAction
->request().url() completionHandler:^(SSBLookupResult* result, NSError* error) { | |
96 // FIXME: Remove logging. | |
97 if (error) | |
98 WTFLogAlways("Error doing SafeBrowsing check"); | |
99 if (!weakThis) | |
100 return; | |
101 bool isUnsafe = false; | |
102 if (result.serviceLookupResults) { | |
103 for (SSBServiceLookupResult* details in result.serviceLookupResults)
{ | |
104 // FIXME: Do we want to keep track of the different types in ord
er to give | |
105 // different warnings? | |
106 if (details.isPhishing || details.isMalware || details.isUnwante
dSoftware || details.isKnownToBeUnsafe) | |
107 isUnsafe = true; | |
108 } | |
109 } | |
110 weakThis->receivedSafeBrowsingDecision(checkRaw, isUnsafe); | |
111 }]; | |
112 #else | |
113 receivedSafeBrowsingDecision(checkRaw, false); | |
114 #endif | |
115 } | |
116 | |
117 void SafeBrowsingController::placeholder() | |
118 { | |
119 [m_webView goBack]; | |
120 } | 103 } |
121 | 104 |
122 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) |
123 { | 106 { |
124 check.navigationPolicyDecision = policy; | 107 check.navigationPolicyDecision = policy; |
125 check.websitePoliciesData = WTFMove(data); | 108 check.websitePoliciesData = WTFMove(data); |
126 maybeFinishedCheck(check); | 109 maybeFinishedCheck(check); |
127 } | 110 } |
128 | 111 |
129 void SafeBrowsingController::receivedSafeBrowsingDecision(SafeBrowsingCheck* che
ck, bool isUnsafe) | 112 void SafeBrowsingController::receivedSafeBrowsingResult(SafeBrowsingCheck* check
, SafeBrowsingResult safeBrowsingResult) |
130 { | 113 { |
131 if (!m_checks.contains(check)) | 114 if (!m_checks.contains(check)) |
132 return; | 115 return; |
133 | 116 |
134 check->safeBrowsingLookUpComplete = true; | 117 check->safeBrowsingResult = safeBrowsingResult; |
135 check->isUnsafe = isUnsafe; | |
136 maybeFinishedCheck(*check); | 118 maybeFinishedCheck(*check); |
137 } | 119 } |
138 | 120 |
139 void SafeBrowsingController::maybeFinishedCheck(SafeBrowsingController::SafeBrow
singCheck& check) | 121 void SafeBrowsingController::maybeFinishedCheck(SafeBrowsingController::SafeBrow
singCheck& check) |
140 { | 122 { |
141 if (!check.navigationPolicyDecision) | 123 if (!check.navigationPolicyDecision) |
142 return; | 124 return; |
143 | 125 |
144 if (check.navigationPolicyDecision.value() == WKNavigationActionPolicyAllow
&& !check.safeBrowsingLookUpComplete) | 126 if (check.navigationPolicyDecision.value() == WKNavigationActionPolicyAllow
&& !check.safeBrowsingResult) |
145 return; | 127 return; |
146 | 128 |
147 switch (check.navigationPolicyDecision.value()) { | 129 switch (check.navigationPolicyDecision.value()) { |
148 case WKNavigationActionPolicyAllow: { | 130 case WKNavigationActionPolicyAllow: { |
149 if (!check.isUnsafe) { | 131 if (check.safeBrowsingResult == SafeBrowsingResult::Safe) { |
150 check.listener->use(WTFMove(check.websitePoliciesData)); | 132 check.listener->use(WTFMove(check.websitePoliciesData)); |
151 return; | 133 break; |
152 } | 134 } |
153 | 135 |
154 auto weakThis = m_weakPtrFactory.createWeakPtr(*this); | 136 check.listener->ignore(); |
155 void (^safeBrowsingPolicyHandler)(WKSafeBrowsingResultPolicy) = ^(WKSafe
BrowsingResultPolicy policy) { | 137 // FIXME: This really needs to be loaded in a way that permits localizat
ion. |
156 if (!weakThis) | 138 // FIXME: Make the warning message more similar to Safari, which means d
ifferent |
157 return; | 139 // wording depending on the type of warning (phishing, malware, etc.). |
158 switch (policy) { | 140 auto targetMainFrameUrl = check.navigationAction->targetFrame()->isMainF
rame() ? check.navigationAction->request().url() : WebCore::URL(WebCore::ParsedU
RLString, check.navigationAction->targetFrame()->page()->currentURL()); |
159 case WKSafeBrowsingResultPolicyCancel: | 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()]; |
160 check.listener->ignore(); | 142 [m_webView _loadAlternateHTMLString:warningString baseURL:WebCore::URL(W
ebCore::ParsedURLString, s_warningPageUrl) forUnreachableURL:targetMainFrameUrl]
; |
161 break; | 143 break; |
162 case WKSafeBrowsingResultPolicyCancelAndShowWarning: { | |
163 check.listener->ignoreAndLockBackForwardList(); | |
164 // FIXME: This really needs to be loaded in a way that permits l
ocalization. | |
165 // Possibly put strings in LocalizedStrings.cpp or LocalizedStri
ngCocoa.mm. | |
166 // Make the warning message similar/identical to Safari, which m
eans different | |
167 // wording depending on the type of warning (phishing, malware,
etc.). | |
168 auto targetMainFrameUrl = check.navigationAction->targetFrame()-
>isMainFrame() ? check.navigationAction->request().url() : WebCore::URL(WebCore:
:ParsedURLString, check.navigationAction->targetFrame()->page()->currentURL()); | |
169 WebCore::LockBackForwardList lockBackForwardList; | |
170 if (check.navigationAction->navigationType() == WebCore::Navigat
ionType::BackForward) | |
171 lockBackForwardList = WebCore::LockBackForwardList::Yes; | |
172 else | |
173 lockBackForwardList = WebCore::LockBackForwardList::No; | |
174 [m_webView _page]->loadAlternateHTMLString([NSString stringWithF
ormat:@"<style>body { background-color: red; }</style><body><h1>This is a simple
SafeBrowsing warning.</h1><h2>You've been warned!!!</h2><h2><a href='%s'>Live d
angerously and visit the site anyway</a></h2>", targetMainFrameUrl.string().utf8
().data()], WebCore::URL(WebCore::ParsedURLString, s_warningPageUrl), targetMain
FrameUrl, nullptr, lockBackForwardList); | |
175 break; | |
176 } | |
177 case WKSafeBrowsingResultPolicyAllow: | |
178 check.listener->use(WTFMove(check.websitePoliciesData)); | |
179 break; | |
180 } | |
181 m_checks.remove(&check); | |
182 }; | |
183 auto navigationDelegate = [m_webView navigationDelegate]; | |
184 if (navigationDelegate && [navigationDelegate respondsToSelector:@select
or(webView:decidePolicyForSafeBrowsingResultForNavigationAction:decisionHandler:
)]) | |
185 [navigationDelegate webView:m_webView decidePolicyForSafeBrowsingRes
ultForNavigationAction:wrapper(check.navigationAction) decisionHandler:safeBrows
ingPolicyHandler]; | |
186 else | |
187 safeBrowsingPolicyHandler(WKSafeBrowsingResultPolicyCancelAndShowWar
ning); | |
188 return; | |
189 } | 144 } |
190 case WKNavigationActionPolicyCancel: | 145 case WKNavigationActionPolicyCancel: |
191 check.listener->ignore(); | 146 check.listener->ignore(); |
192 break; | 147 break; |
193 case _WKNavigationActionPolicyDownload: | 148 case _WKNavigationActionPolicyDownload: |
194 check.listener->download(); | 149 check.listener->download(); |
195 break; | 150 break; |
196 default: | 151 default: |
197 ASSERT_NOT_REACHED(); | 152 ASSERT_NOT_REACHED(); |
198 } | 153 } |
199 m_checks.remove(&check); | 154 m_checks.remove(&check); |
200 } | 155 } |
201 | 156 |
202 } // namespace WebKit | 157 } // namespace WebKit |
203 | 158 |
204 #endif // WK_API_ENABLED | 159 #endif // WK_API_ENABLED |
LEFT | RIGHT |