Modified: trunk/Source/WebCore/page/WebKitNamespace.cpp (259330 => 259331)
--- trunk/Source/WebCore/page/WebKitNamespace.cpp 2020-04-01 01:22:59 UTC (rev 259330)
+++ trunk/Source/WebCore/page/WebKitNamespace.cpp 2020-04-01 01:42:53 UTC (rev 259331)
@@ -26,6 +26,12 @@
#include "config.h"
#include "WebKitNamespace.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "Logging.h"
+
+#define RELEASE_LOG_ERROR_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_ERROR_IF(frame() && frame()->isAlwaysOnLoggingAllowed(), channel, "%p - WebKitNamespace::" fmt, this, ##__VA_ARGS__)
+
#if ENABLE(USER_MESSAGE_HANDLERS)
#include "DOMWindow.h"
@@ -44,6 +50,11 @@
UserMessageHandlersNamespace* WebKitNamespace::messageHandlers()
{
+ if (frame() && frame()->loader().client().hasNavigatedAwayFromAppBoundDomain()) {
+ RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "Ignoring messageHandlers() request for non app-bound domain");
+ return nullptr;
+ }
+
return &m_messageHandlerNamespace.get();
}
@@ -50,3 +61,5 @@
} // namespace WebCore
#endif // ENABLE(USER_MESSAGE_HANDLERS)
+
+#undef RELEASE_LOG_ERROR_IF_ALLOWED
Modified: trunk/Tools/ChangeLog (259330 => 259331)
--- trunk/Tools/ChangeLog 2020-04-01 01:22:59 UTC (rev 259330)
+++ trunk/Tools/ChangeLog 2020-04-01 01:42:53 UTC (rev 259331)
@@ -1,3 +1,30 @@
+2020-03-31 Kate Cheney <[email protected]>
+
+ Requests for messageHandlers() in the DOMWindow should be ignored for non-app-bound navigations
+ https://bugs.webkit.org/show_bug.cgi?id=209836
+ <rdar://problem/61071607>
+
+ Reviewed by Brent Fulgham.
+
+ Most of this patch is changes to the tests, which formerly relied
+ on message handlers to test script injection protections. I rewrote
+ three tests to remove the use of message handlers which were used to
+ confirm normal script injection behavior before enabling In-App
+ Browser Privacy. Since normal script injection behavior is tested in
+ WKUserContentController.mm already it is unecessary to test here.
+
+ I removed one test, IgnoreAppBoundDomainsAcceptsUserScripts, which
+ fully relied on message handler use and could not be tested without
+ somehow disabling this feature.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
+ (TEST):
+ (-[TestInAppBrowserScriptMessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
+ * TestWebKitAPI/Tests/WebKitCocoa/in-app-browser-privacy-local-file.html:
+ Add a message handler to this page to demonstrate that message
+ handlers work for app-bound navigations (file:// protocol is always
+ app-bound).
+
2020-03-31 Alex Christensen <[email protected]>
Send correct UserContentControllerIdentifier after using SPI WKWebpagePreferences._userContentController
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm (259330 => 259331)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm 2020-04-01 01:22:59 UTC (rev 259330)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm 2020-04-01 01:42:53 UTC (rev 259331)
@@ -48,18 +48,6 @@
static NSString * const userScriptSource = @"window.wkUserScriptInjected = true";
-@interface TestInAppBrowserScriptMessageHandler : NSObject <WKScriptMessageHandler>
-@end
-
-@implementation TestInAppBrowserScriptMessageHandler
-
-- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
-{
- isDone = true;
-}
-
-@end
-
@interface InAppBrowserSchemeHandler : NSObject <WKURLSchemeHandler>
@end
@@ -69,7 +57,7 @@
{
NSString *response = nil;
if ([task.request.URL.path isEqualToString:@"/in-app-browser-privacy-test-user-script"])
- response = @"<script>window.webkit.messageHandlers.testInAppBrowserPrivacy.postMessage(\"done\");</script>";
+ response = @"<script>window.wkUserScriptInjected = false;</script>";
else if ([task.request.URL.path isEqualToString:@"/in-app-browser-privacy-test-user-agent-script"])
response = @"<script> window.wkUserScriptInjected = true; </script>";
else if ([task.request.URL.path isEqualToString:@"/in-app-browser-privacy-test-user-style-sheets"])
@@ -76,6 +64,8 @@
response = @"<body style='background-color: red;'></body>";
else if ([task.request.URL.path isEqualToString:@"/in-app-browser-privacy-test-user-style-sheets-iframe"])
response = @"<body style='background-color: red;'><iframe src=''></iframe></body>";
+ else if ([task.request.URL.path isEqualToString:@"/in-app-browser-privacy-test-message-handler"])
+ response = @"<body style='background-color: green;'></body><script>if (window.webkit.messageHandlers)\nwindow.webkit.messageHandlers.testHandler.postMessage('Failed'); \nelse \n document.body.style.background = '';</script>";
[task didReceiveResponse:[[[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:response.length textEncodingName:nil] autorelease]];
[task didReceiveData:[response dataUsingEncoding:NSUTF8StringEncoding]];
@@ -97,47 +87,24 @@
TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtStart)
{
- auto messageHandler = adoptNS([[TestInAppBrowserScriptMessageHandler alloc] init]);
+ isDone = false;
+ initializeInAppBrowserPrivacyTestSettings();
auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
- // First set up the configuration without In-App Browser Privacy settings to ensure it works as expected.
WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
- [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
- [[configuration preferences] _setInAppBrowserPrivacyEnabled:NO];
-
auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-
[configuration.userContentController addUserScript:userScript.get()];
- [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testInAppBrowserPrivacy"];
+ [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
+ [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-script"]];
[webView loadRequest:request];
[webView _test_waitForDidFinishNavigation];
- TestWebKitAPI::Util::run(&isDone);
-
- [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
- EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
- EXPECT_FALSE(!!error);
- isDone = true;
- }];
- isDone = false;
- TestWebKitAPI::Util::run(&isDone);
-
- // Now setup In-App Browser Privacy settings and expect a failed script evaluation result, and an error message.
- isDone = false;
- initializeInAppBrowserPrivacyTestSettings();
- [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
- [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
-
- auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
- [webView2 loadRequest:request];
- TestWebKitAPI::Util::run(&isDone);
-
// Check that request to read this variable is rejected.
- [webView2 evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
+ [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
EXPECT_FALSE(result);
EXPECT_TRUE(!!error);
isDone = true;
@@ -148,9 +115,9 @@
// Turn back on In-App Browser Privacy quirks to check that original attempt to set this variable was rejected.
isDone = false;
- [[[webView2 configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
- [webView2 evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
- EXPECT_EQ(NO, [[webView2 objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
+ [[[webView configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
+ [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
+ EXPECT_EQ(NO, [result boolValue]);
EXPECT_FALSE(!!error);
isDone = true;
}];
@@ -161,47 +128,24 @@
TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtEnd)
{
- auto messageHandler = adoptNS([[TestInAppBrowserScriptMessageHandler alloc] init]);
+ isDone = false;
+ initializeInAppBrowserPrivacyTestSettings();
auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]);
-
- // First set up the configuration without In-App Browser Privacy settings to ensure it works as expected.
+
WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
- [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
- [[configuration preferences] _setInAppBrowserPrivacyEnabled:NO];
-
auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-
[configuration.userContentController addUserScript:userScript.get()];
- [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testInAppBrowserPrivacy"];
+ [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
+ [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-script"]];
[webView loadRequest:request];
[webView _test_waitForDidFinishNavigation];
- TestWebKitAPI::Util::run(&isDone);
-
- [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
- EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
- EXPECT_FALSE(!!error);
- isDone = true;
- }];
- isDone = false;
- TestWebKitAPI::Util::run(&isDone);
-
- // Now setup In-App Browser Privacy settings and expect a failed script evaluation result, and an error message.
- isDone = false;
- initializeInAppBrowserPrivacyTestSettings();
- [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
- [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
-
- auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
- [webView2 loadRequest:request];
- TestWebKitAPI::Util::run(&isDone);
-
// Check that request to read this variable is rejected.
- [webView2 evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
+ [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
EXPECT_FALSE(result);
EXPECT_TRUE(!!error);
isDone = true;
@@ -212,9 +156,9 @@
// Turn back on In-App Browser Privacy quirks to check that original attempt to set this variable was rejected.
isDone = false;
- [[[webView2 configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
- [webView2 evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
- EXPECT_EQ(NO, [[webView2 objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
+ [[[webView configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
+ [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
+ EXPECT_EQ(NO, [result boolValue]);
EXPECT_FALSE(!!error);
isDone = true;
}];
@@ -238,7 +182,7 @@
[webView _test_waitForDidFinishNavigation];
[webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
- EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
+ EXPECT_EQ(YES, [result boolValue]);
isDone = true;
}];
@@ -268,11 +212,9 @@
TEST(InAppBrowserPrivacy, SwapBackToAppBoundRejectsUserScript)
{
initializeInAppBrowserPrivacyTestSettings();
- auto messageHandler = adoptNS([[TestInAppBrowserScriptMessageHandler alloc] init]);
auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
- [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testInAppBrowserPrivacy"];
[[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
[[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
@@ -283,7 +225,6 @@
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-script"]];
[webView loadRequest:request];
[webView _test_waitForDidFinishNavigation];
- TestWebKitAPI::Util::run(&isDone);
[configuration.userContentController _addUserScriptImmediately:userScript.get()];
[webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
@@ -386,39 +327,6 @@
TestWebKitAPI::Util::run(&isDone);
}
-TEST(InAppBrowserPrivacy, IgnoreAppBoundDomainsAcceptsUserScripts)
-{
- initializeInAppBrowserPrivacyTestSettings();
- auto messageHandler = adoptNS([[TestInAppBrowserScriptMessageHandler alloc] init]);
- auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
-
- WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
- [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testInAppBrowserPrivacy"];
- [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
- [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
- [configuration _setIgnoresAppBoundDomains:YES];
-
- auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
- [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-
- auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
- NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-script"]];
-
- [webView loadRequest:request];
- [webView _test_waitForDidFinishNavigation];
- TestWebKitAPI::Util::run(&isDone);
-
- [configuration.userContentController _addUserScriptImmediately:userScript.get()];
- [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
- EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
- EXPECT_FALSE(!!error);
- isDone = true;
- }];
-
- isDone = false;
- TestWebKitAPI::Util::run(&isDone);
-}
-
static NSString *styleSheetSource = @"body { background-color: green !important; }";
static NSString *backgroundColorScript = @"window.getComputedStyle(document.body, null).getPropertyValue('background-color')";
static NSString *frameBackgroundColorScript = @"window.getComputedStyle(document.getElementsByTagName('iframe')[0].contentDocument.body, null).getPropertyValue('background-color')";
@@ -506,6 +414,70 @@
expectScriptEvaluatesToColor(webView.get(), frameBackgroundColorScript, redInRGB);
}
+TEST(InAppBrowserPrivacy, NonAppBoundDomainCannotAccessMessageHandlers)
+{
+ initializeInAppBrowserPrivacyTestSettings();
+ isDone = false;
+
+ RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+
+ auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
+ [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
+ [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
+
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
+
+ [webView performAfterReceivingMessage:@"Failed" action:^() {
+ FAIL();
+ }];
+
+ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-message-handler"]];
+ [webView loadRequest:request];
+ [webView _test_waitForDidFinishNavigation];
+
+ // Set the background color to red if message handlers returned null so we can
+ // check without needing a message handler.
+ expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+}
+
+TEST(InAppBrowserPrivacy, AppBoundToNonAppBoundDomainCannotAccessMessageHandlers)
+{
+ initializeInAppBrowserPrivacyTestSettings();
+ isDone = false;
+
+ RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+
+ auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
+ [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
+ [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
+
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
+
+ [webView performAfterReceivingMessage:@"Passed" action:^() {
+ isDone = true;
+ }];
+
+ // Navigate to an app-bound domain and wait for the 'pass' message to test the handler is working fine.
+ NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"in-app-browser-privacy-local-file" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+ [webView loadRequest:request];
+ [webView _test_waitForDidFinishNavigation];
+
+ TestWebKitAPI::Util::run(&isDone);
+
+ [webView performAfterReceivingMessage:@"Failed" action:^() {
+ FAIL();
+ }];
+
+ // Navigate away from an app-bound domain.
+ NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-message-handler"]];
+ [webView loadRequest:request2];
+ [webView _test_waitForDidFinishNavigation];
+
+ // Set the background color to red if message handlers returned null so we can
+ // check without needing a message handler.
+ expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+}
+
#endif // USE(APPLE_INTERNAL_SDK)
#endif // PLATFORM(IOS_FAMILY)