Modified: trunk/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp (259519 => 259520)
--- trunk/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp 2020-04-03 22:55:59 UTC (rev 259519)
+++ trunk/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp 2020-04-03 23:39:06 UTC (rev 259520)
@@ -29,11 +29,19 @@
#include "WebCookieManagerProxy.h"
#include "WebProcessPool.h"
#include "WebsiteDataStore.h"
+#include "WebsiteDataStoreParameters.h"
#include <WebCore/Cookie.h>
#include <WebCore/CookieStorage.h>
#include <WebCore/HTTPCookieAcceptPolicy.h>
#include <WebCore/NetworkStorageSession.h>
+#if USE(APPLE_INTERNAL_SDK)
+#include <WebKitAdditions/HTTPCookieStoreAdditions.h>
+#else
+#define IN_APP_BROWSER_PRIVACY_ENABLED false
+#define IMPLEMENT_IN_APP_BROWSER_PRIVACY_ENABLED
+#endif
+
using namespace WebKit;
namespace API {
@@ -54,6 +62,27 @@
unregisterForNewProcessPoolNotifications();
}
+void HTTPCookieStore::filterAppBoundCookies(const Vector<WebCore::Cookie>& cookies, CompletionHandler<void(Vector<WebCore::Cookie>&&)>&& completionHandler)
+{
+ Vector<WebCore::Cookie> appBoundCookies;
+#if PLATFORM(IOS_FAMILY)
+ m_owningDataStore->getAppBoundDomains([this, protectedThis = makeRef(*this), cookies, appBoundCookies = WTFMove(appBoundCookies), completionHandler = WTFMove(completionHandler)] (auto& domains) mutable {
+ if (m_owningDataStore->parameters().networkSessionParameters.isInAppBrowserPrivacyEnabled || IN_APP_BROWSER_PRIVACY_ENABLED) {
+ IMPLEMENT_IN_APP_BROWSER_PRIVACY_ENABLED
+ for (auto& cookie : cookies) {
+ if (domains.contains(WebCore::RegistrableDomain::uncheckedCreateFromHost(cookie.domain)))
+ appBoundCookies.append(cookie);
+ }
+ } else
+ appBoundCookies = cookies;
+ completionHandler(WTFMove(appBoundCookies));
+ });
+#else
+ appBoundCookies = cookies;
+ completionHandler(WTFMove(appBoundCookies));
+#endif
+}
+
void HTTPCookieStore::cookies(CompletionHandler<void(const Vector<WebCore::Cookie>&)>&& completionHandler)
{
auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
@@ -63,15 +92,15 @@
allCookies = getAllDefaultUIProcessCookieStoreCookies();
allCookies.appendVector(m_owningDataStore->pendingCookies());
- RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), allCookies] () mutable {
- completionHandler(allCookies);
+ RunLoop::main().dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), allCookies] () mutable {
+ filterAppBoundCookies(allCookies, WTFMove(completionHandler));
});
return;
}
auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
- cookieManager->getAllCookies(m_owningDataStore->sessionID(), [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] (const Vector<WebCore::Cookie>& cookies) mutable {
- completionHandler(cookies);
+ cookieManager->getAllCookies(m_owningDataStore->sessionID(), [this, protectedThis = makeRef(*this), pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] (const Vector<WebCore::Cookie>& cookies) mutable {
+ filterAppBoundCookies(cookies, WTFMove(completionHandler));
});
}
@@ -82,30 +111,32 @@
return completionHandler({ });
auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
- cookieManager->getCookies(m_owningDataStore->sessionID(), url, [completionHandler = WTFMove(completionHandler)] (Vector<WebCore::Cookie>&& cookies) mutable {
- completionHandler(WTFMove(cookies));
+ cookieManager->getCookies(m_owningDataStore->sessionID(), url, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (Vector<WebCore::Cookie>&& cookies) mutable {
+ filterAppBoundCookies(cookies, WTFMove(completionHandler));
});
}
void HTTPCookieStore::setCookies(const Vector<WebCore::Cookie>& cookies, CompletionHandler<void()>&& completionHandler)
{
- auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
- if (!pool) {
- for (auto& cookie : cookies) {
- // FIXME: pendingCookies used for defaultSession because session cookies cannot be propagated to Network Process with uiProcessCookieStorageIdentifier.
- if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
- setCookieInDefaultUIProcessCookieStore(cookie);
- else
- m_owningDataStore->addPendingCookie(cookie);
+ filterAppBoundCookies(cookies, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (auto&& appBoundCookies) mutable {
+ auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
+ if (!pool) {
+ for (auto& cookie : appBoundCookies) {
+ // FIXME: pendingCookies used for defaultSession because session cookies cannot be propagated to Network Process with uiProcessCookieStorageIdentifier.
+ if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
+ setCookieInDefaultUIProcessCookieStore(cookie);
+ else
+ m_owningDataStore->addPendingCookie(cookie);
+ }
+
+ RunLoop::main().dispatch(WTFMove(completionHandler));
+ return;
}
- RunLoop::main().dispatch(WTFMove(completionHandler));
- return;
- }
-
- auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
- cookieManager->setCookies(m_owningDataStore->sessionID(), cookies, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] () mutable {
- completionHandler();
+ auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
+ cookieManager->setCookies(m_owningDataStore->sessionID(), appBoundCookies, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)] () mutable {
+ completionHandler();
+ });
});
}
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm (259519 => 259520)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm 2020-04-03 22:55:59 UTC (rev 259519)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm 2020-04-03 23:39:06 UTC (rev 259520)
@@ -31,6 +31,7 @@
#import "WKWebViewConfigurationExtras.h"
#import <WebCore/RegistrableDomain.h>
#import <WebCore/RuntimeApplicationChecks.h>
+#import <WebKit/WKHTTPCookieStorePrivate.h>
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/WKUserContentControllerPrivate.h>
#import <WebKit/WKWebsiteDataStorePrivate.h>
@@ -78,6 +79,11 @@
@end
+static void cleanUpInAppBrowserPrivacyTestSettings()
+{
+ IN_APP_BROWSER_PRIVACY_ADDITIONS_2
+}
+
static void initializeInAppBrowserPrivacyTestSettings()
{
RunLoop::initializeMainRunLoop();
@@ -119,6 +125,7 @@
[webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
EXPECT_EQ(NO, [result boolValue]);
EXPECT_FALSE(!!error);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
@@ -160,6 +167,7 @@
[webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
EXPECT_EQ(NO, [result boolValue]);
EXPECT_FALSE(!!error);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
@@ -202,6 +210,7 @@
[webView2 evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
EXPECT_FALSE(result);
EXPECT_TRUE(!!error);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
@@ -245,6 +254,7 @@
[webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
EXPECT_FALSE(result);
EXPECT_TRUE(!!error);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
@@ -265,6 +275,7 @@
for (int i = 0; i < length; i++)
EXPECT_WK_STREQ([sortedDomains objectAtIndex:i], [domainsToCompare objectAtIndex:i]);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
TestWebKitAPI::Util::run(&isDone);
@@ -284,6 +295,7 @@
isDone = false;
[webView _isNavigatingToAppBoundDomain:^(BOOL isAppBound) {
EXPECT_TRUE(isAppBound);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
TestWebKitAPI::Util::run(&isDone);
@@ -302,6 +314,7 @@
isDone = false;
[webView _isNavigatingToAppBoundDomain:^(BOOL isAppBound) {
EXPECT_TRUE(isAppBound);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
TestWebKitAPI::Util::run(&isDone);
@@ -320,6 +333,7 @@
isDone = false;
[webView _isNavigatingToAppBoundDomain:^(BOOL isAppBound) {
EXPECT_TRUE(isAppBound);
+ cleanUpInAppBrowserPrivacyTestSettings();
isDone = true;
}];
TestWebKitAPI::Util::run(&isDone);
@@ -364,6 +378,7 @@
[[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+ cleanUpInAppBrowserPrivacyTestSettings();
}
TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetForAllWebViewsFails)
@@ -385,6 +400,7 @@
[[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+ cleanUpInAppBrowserPrivacyTestSettings();
}
TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetAffectingAllFramesFails)
@@ -410,6 +426,7 @@
// The subframe should also be affected.
expectScriptEvaluatesToColor(webView.get(), frameBackgroundColorScript, redInRGB);
+ cleanUpInAppBrowserPrivacyTestSettings();
}
TEST(InAppBrowserPrivacy, NonAppBoundDomainCannotAccessMessageHandlers)
@@ -436,6 +453,7 @@
// 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);
+ cleanUpInAppBrowserPrivacyTestSettings();
}
TEST(InAppBrowserPrivacy, AppBoundToNonAppBoundDomainCannotAccessMessageHandlers)
@@ -474,8 +492,256 @@
// 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);
+ cleanUpInAppBrowserPrivacyTestSettings();
}
+static RetainPtr<WKHTTPCookieStore> globalCookieStore;
+static bool gotFlag = false;
+
+static void setUpCookieTest()
+{
+ globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore];
+ NSArray<NSHTTPCookie *> *cookies = nil;
+ [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+ *cookiesPtr = [nsCookies retain];
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ for (id cookie in cookies) {
+ gotFlag = false;
+ [globalCookieStore deleteCookie:cookie completionHandler:[]() {
+ gotFlag = true;
+ }];
+ TestWebKitAPI::Util::run(&gotFlag);
+ }
+
+ cookies = nil;
+ gotFlag = false;
+ [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+ *cookiesPtr = [nsCookies retain];
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ // Make sure the cookie store starts out empty.
+ ASSERT_EQ(cookies.count, 0u);
+ [cookies release];
+
+ gotFlag = false;
+}
+
+TEST(InAppBrowserPrivacy, SetCookieForNonAppBoundDomainFails)
+{
+ initializeInAppBrowserPrivacyTestSettings();
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+
+ auto dataStore = [WKWebsiteDataStore defaultDataStore];
+ auto webView = adoptNS([TestWKWebView new]);
+ [webView loadHTMLString:@"Oh hello" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+ [webView _test_waitForDidFinishNavigation];
+
+ setUpCookieTest();
+ globalCookieStore = [dataStore httpCookieStore];
+
+ NSArray<NSHTTPCookie *> *cookies = nil;
+
+ // Non app-bound cookie.
+ RetainPtr<NSHTTPCookie> nonAppBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+ NSHTTPCookiePath: @"/",
+ NSHTTPCookieName: @"nonAppBoundName",
+ NSHTTPCookieValue: @"nonAppBoundValue",
+ NSHTTPCookieDomain: @"nonAppBoundDomain.com",
+ }];
+
+ // App-bound cookie.
+ RetainPtr<NSHTTPCookie> appBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+ NSHTTPCookiePath: @"/",
+ NSHTTPCookieName: @"webKitName",
+ NSHTTPCookieValue: @"webKitValue",
+ NSHTTPCookieDomain: @"www.webkit.org",
+ }];
+
+ gotFlag = false;
+ // This should not actually set a cookie.
+ [globalCookieStore setCookie:nonAppBoundCookie.get() completionHandler:[]() {
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+ gotFlag = false;
+
+ // This should successfully set a cookie.
+ [globalCookieStore setCookie:appBoundCookie.get() completionHandler:[]() {
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ cleanUpInAppBrowserPrivacyTestSettings();
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+ gotFlag = false;
+
+ // Check the cookie store to make sure only one cookie was set.
+ [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+ *cookiesPtr = [nsCookies retain];
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ ASSERT_EQ(cookies.count, 1u);
+
+ [cookies release];
+ gotFlag = false;
+ [globalCookieStore deleteCookie:appBoundCookie.get() completionHandler:[]() {
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+}
+
+TEST(InAppBrowserPrivacy, GetCookieForNonAppBoundDomainFails)
+{
+ // Since we can't set non-app-bound cookies with In-App Browser privacy protections on,
+ // we can turn the protections off to set a cookie we will then try to get with protections enabled.
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+
+ setUpCookieTest();
+ globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore];
+ NSArray<NSHTTPCookie *> *cookies = nil;
+
+ // Non app-bound cookie.
+ RetainPtr<NSHTTPCookie> nonAppBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+ NSHTTPCookiePath: @"/",
+ NSHTTPCookieName: @"CookieName",
+ NSHTTPCookieValue: @"CookieValue",
+ NSHTTPCookieDomain: @"nonAppBoundDomain.com",
+ }];
+
+ // App-bound cookie.
+ RetainPtr<NSHTTPCookie> appBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+ NSHTTPCookiePath: @"/",
+ NSHTTPCookieName: @"OtherCookieName",
+ NSHTTPCookieValue: @"OtherCookieValue",
+ NSHTTPCookieDomain: @"www.webkit.org",
+ }];
+
+ auto webView = adoptNS([TestWKWebView new]);
+ [webView synchronouslyLoadHTMLString:@"start network process"];
+
+ // This should successfully set a cookie because protections are off.
+ [globalCookieStore setCookie:nonAppBoundCookie.get() completionHandler:[]() {
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+ gotFlag = false;
+
+ [globalCookieStore setCookie:appBoundCookie.get() completionHandler:[]() {
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ gotFlag = false;
+ [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+ *cookiesPtr = [nsCookies retain];
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ // Confirm both cookies are in the store.
+ ASSERT_EQ(cookies.count, 2u);
+
+ // Now enable protections and ensure we can only retrieve the app-bound cookies.
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+ initializeInAppBrowserPrivacyTestSettings();
+
+ gotFlag = false;
+ [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
+ *cookiesPtr = [nsCookies retain];
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ ASSERT_EQ(cookies.count, 1u);
+
+ [cookies release];
+
+ gotFlag = false;
+ [globalCookieStore deleteCookie:nonAppBoundCookie.get() completionHandler:[]() {
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+
+ gotFlag = false;
+ [globalCookieStore deleteCookie:appBoundCookie.get() completionHandler:[]() {
+ // Reset flag.
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+ cleanUpInAppBrowserPrivacyTestSettings();
+ gotFlag = true;
+ }];
+
+ TestWebKitAPI::Util::run(&gotFlag);
+}
+
+TEST(InAppBrowserPrivacy, GetCookieForURLFails)
+{
+ // Since we can't set non-app-bound cookies with In-App Browser privacy protections on,
+ // we can turn the protections off to set a cookie we will then try to get with protections enabled.
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+ setUpCookieTest();
+
+ globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore];
+ NSHTTPCookie *nonAppBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+ NSHTTPCookiePath: @"/",
+ NSHTTPCookieName: @"nonAppBoundName",
+ NSHTTPCookieValue: @"nonAppBoundValue",
+ NSHTTPCookieDomain: @"nonAppBoundDomain.com",
+ }];
+
+ NSHTTPCookie *appBoundCookie = [NSHTTPCookie cookieWithProperties:@{
+ NSHTTPCookiePath: @"/",
+ NSHTTPCookieName: @"webKitName",
+ NSHTTPCookieValue: @"webKitValue",
+ NSHTTPCookieDomain: @"webkit.org",
+ }];
+
+ __block bool done = false;
+ auto webView = adoptNS([TestWKWebView new]);
+ [webView synchronouslyLoadHTMLString:@"start network process"];
+ [globalCookieStore setCookie:nonAppBoundCookie completionHandler:^{
+ [globalCookieStore setCookie:appBoundCookie completionHandler:^{
+
+ // Now enable protections and ensure we can only retrieve the app-bound cookies.
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+ initializeInAppBrowserPrivacyTestSettings();
+
+ [globalCookieStore _getCookiesForURL:[NSURL URLWithString:@"https://webkit.org/"] completionHandler:^(NSArray<NSHTTPCookie *> *cookies) {
+ EXPECT_EQ(cookies.count, 1ull);
+ EXPECT_WK_STREQ(cookies[0].name, "webKitName");
+ [globalCookieStore _getCookiesForURL:[NSURL URLWithString:@"https://nonAppBoundDomain.com/"] completionHandler:^(NSArray<NSHTTPCookie *> *cookies) {
+ EXPECT_EQ(cookies.count, 0u);
+ [globalCookieStore deleteCookie:nonAppBoundCookie completionHandler:^{
+ [globalCookieStore deleteCookie:appBoundCookie completionHandler:^{
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDebugIsInAppBrowserPrivacyEnabled"];
+ cleanUpInAppBrowserPrivacyTestSettings();
+ done = true;
+ }];
+ }];
+ }];
+ }];
+ }];
+ }];
+ TestWebKitAPI::Util::run(&done);
+}
+
#endif // USE(APPLE_INTERNAL_SDK)
#endif // PLATFORM(IOS_FAMILY)