/* * Copyright (C) 2019 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "PlatformUtilities.h" #import "TestWKWebView.h" #import "UIKitSPI.h" #import #import #import #import @interface TestWKWebView (ClipboardTests) - (void)readClipboard; @end @implementation TestWKWebView (ClipboardTests) - (void)readClipboard { __block bool done = false; [self performAfterReceivingMessage:@"readClipboard" action:^{ done = true; }]; [self evaluateJavaScript:@"readClipboard()" completionHandler:nil]; TestWebKitAPI::Util::run(&done); } - (void)writeString:(NSString *)string toClipboardWithType:(NSString *)type { __block bool done = false; [self performAfterReceivingMessage:@"wroteStringToClipboard" action:^{ done = true; }]; [self evaluateJavaScript:[NSString stringWithFormat:@"writeStringToClipboard(`%@`, `%@`)", type, string] completionHandler:nil]; TestWebKitAPI::Util::run(&done); } @end static RetainPtr createWebViewForClipboardTests() { #if PLATFORM(IOS_FAMILY) static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // UIPasteboard's type coercion codepaths only take effect when the UIApplication has been initialized. UIApplicationInitialize(); }); #endif // PLATFORM(IOS_FAMILY) auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); [[configuration preferences] _setDOMPasteAllowed:YES]; [[configuration preferences] _setJavaScriptCanAccessClipboard:YES]; for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) { if ([feature.key isEqualToString:@"AsyncClipboardAPIEnabled"]) { [[configuration preferences] _setEnabled:YES forExperimentalFeature:feature]; break; } } auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]); [webView synchronouslyLoadTestPageNamed:@"clipboard"]; return webView; } static void writeMultipleObjectsToPlatformPasteboard() { #if PLATFORM(MAC) auto firstItem = adoptNS([[NSPasteboardItem alloc] init]); [firstItem setString:@"Hello" forType:NSPasteboardTypeString]; auto secondItem = adoptNS([[NSPasteboardItem alloc] init]); [secondItem setString:@"https://apple.com/" forType:NSPasteboardTypeURL]; auto thirdItem = adoptNS([[NSPasteboardItem alloc] init]); [thirdItem setString:@"Hello world" forType:NSPasteboardTypeHTML]; auto fourthItem = adoptNS([[NSPasteboardItem alloc] init]); [fourthItem setString:@"WebKit" forType:NSPasteboardTypeString]; [fourthItem setString:@"https://webkit.org/" forType:NSPasteboardTypeURL]; [fourthItem setString:@"Hello world" forType:NSPasteboardTypeHTML]; NSPasteboard *pasteboard = NSPasteboard.generalPasteboard; [pasteboard clearContents]; [pasteboard writeObjects:@[firstItem.get(), secondItem.get(), thirdItem.get(), fourthItem.get()]]; #elif PLATFORM(IOS_FAMILY) && !PLATFORM(WATCHOS) && !PLATFORM(APPLETV) auto firstItem = adoptNS([[NSItemProvider alloc] initWithObject:@"Hello"]); auto secondItem = adoptNS([[NSItemProvider alloc] initWithObject:[NSURL URLWithString:@"https://apple.com/"]]); auto thirdItem = adoptNS([[NSItemProvider alloc] init]); [thirdItem registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeHTML visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[&] (void (^completionHandler)(NSData *, NSError *)) -> NSProgress * { completionHandler([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil); return nil; }]; auto fourthItem = adoptNS([[NSItemProvider alloc] init]); [fourthItem registerObject:@"WebKit" visibility:NSItemProviderRepresentationVisibilityAll]; [fourthItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:NSItemProviderRepresentationVisibilityAll]; [fourthItem registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeHTML visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[&] (void (^completionHandler)(NSData *, NSError *)) -> NSProgress * { completionHandler([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil); return nil; }]; UIPasteboard.generalPasteboard.itemProviders = @[ firstItem.get(), secondItem.get(), thirdItem.get(), fourthItem.get() ]; #endif } static RetainPtr readMarkupFromPasteboard() { #if PLATFORM(MAC) NSData *rawData = [NSPasteboard.generalPasteboard dataForType:WebCore::legacyHTMLPasteboardType()]; #else NSData *rawData = [UIPasteboard.generalPasteboard dataForPasteboardType:(__bridge NSString *)kUTTypeHTML]; #endif return adoptNS([[NSString alloc] initWithData:rawData encoding:NSUTF8StringEncoding]); } TEST(ClipboardTests, ReadMultipleItems) { auto webView = createWebViewForClipboardTests(); writeMultipleObjectsToPlatformPasteboard(); [webView readClipboard]; EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"exception ? exception.message : ''"]); EXPECT_EQ(4U, [[webView objectByEvaluatingJavaScript:@"clipboardData.length"] unsignedIntValue]); EXPECT_WK_STREQ("Hello", [webView stringByEvaluatingJavaScript:@"clipboardData[0]['text/plain']"]); EXPECT_WK_STREQ("https://apple.com/", [webView stringByEvaluatingJavaScript:@"clipboardData[1]['text/uri-list']"]); EXPECT_WK_STREQ("rgb(0, 255, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(clipboardData[2]['text/html'].querySelector('strong')).color"]); EXPECT_WK_STREQ("WebKit", [webView stringByEvaluatingJavaScript:@"clipboardData[3]['text/plain']"]); EXPECT_WK_STREQ("https://webkit.org/", [webView objectByEvaluatingJavaScript:@"clipboardData[3]['text/uri-list']"]); EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"clipboardData[3]['text/html'].querySelector('a').href"]); } TEST(ClipboardTests, WriteSanitizedMarkup) { auto webView = createWebViewForClipboardTests(); [webView writeString:@"This is a test." toClipboardWithType:@"text/html"]; auto writtenMarkup = readMarkupFromPasteboard(); EXPECT_TRUE([writtenMarkup containsString:@"This is a test."]); EXPECT_FALSE([writtenMarkup containsString:@"super secret"]); EXPECT_FALSE([writtenMarkup containsString:@"