/* * Copyright (C) 2017 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" #if PLATFORM(COCOA) #import "PasteboardUtilities.h" #import "PlatformUtilities.h" #import "TestWKWebView.h" #import #import #import #import #if PLATFORM(IOS_FAMILY) #import #endif @interface WKWebView () - (void)copy:(id)sender; - (void)paste:(id)sender; @end #if PLATFORM(MAC) @interface WKWebView () @end NSData *readHTMLDataFromPasteboard() { return [[NSPasteboard generalPasteboard] dataForType:NSHTMLPboardType]; } NSString *readHTMLStringFromPasteboard() { return [[NSPasteboard generalPasteboard] stringForType:NSHTMLPboardType]; } #else NSData *readHTMLDataFromPasteboard() { return [[UIPasteboard generalPasteboard] dataForPasteboardType:(__bridge NSString *)kUTTypeHTML]; } NSString *readHTMLStringFromPasteboard() { RetainPtr value = [[UIPasteboard generalPasteboard] valueForPasteboardType:(__bridge NSString *)kUTTypeHTML]; if ([value isKindOfClass:[NSData class]]) value = adoptNS([[NSString alloc] initWithData:(NSData *)value encoding:NSUTF8StringEncoding]); ASSERT([value isKindOfClass:[NSString class]]); return (NSString *)value.autorelease(); } #endif TEST(CopyHTML, Sanitizes) { auto webView = createWebViewWithCustomPasteboardDataEnabled(); [webView synchronouslyLoadTestPageNamed:@"copy-html"]; [webView stringByEvaluatingJavaScript:@"HTMLToCopy = 'hello" ", world';"]; [webView copy:nil]; [webView paste:nil]; EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"didCopy"].boolValue); EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"didPaste"].boolValue); EXPECT_WK_STREQ("hello, world", [webView stringByEvaluatingJavaScript:@"pastedHTML"]); String htmlInNativePasteboard = readHTMLStringFromPasteboard(); EXPECT_TRUE(htmlInNativePasteboard.contains("hello"_s)); EXPECT_TRUE(htmlInNativePasteboard.contains(", world"_s)); EXPECT_FALSE(htmlInNativePasteboard.contains("secret"_s)); EXPECT_FALSE(htmlInNativePasteboard.contains("dangerousCode"_s)); } TEST(CopyHTML, SanitizationPreservesCharacterSetInSelectedText) { auto webView = createWebViewWithCustomPasteboardDataEnabled(); [webView synchronouslyLoadHTMLString:@"" "" "" "我叫謝文昇" "" ""]; [webView copy:nil]; [webView waitForNextPresentationUpdate]; NSString *copiedMarkup = readHTMLStringFromPasteboard(); EXPECT_TRUE([copiedMarkup containsString:@""]); auto attributedString = adoptNS([[NSAttributedString alloc] initWithData:readHTMLDataFromPasteboard() options:@{ NSDocumentTypeDocumentOption: NSHTMLTextDocumentType } documentAttributes:nil error:nil]); EXPECT_WK_STREQ("我叫謝文昇", [attributedString string]); } TEST(CopyHTML, SanitizationPreservesCharacterSet) { Vector, RetainPtr>, 3> markupStringsAndData; auto webView = createWebViewWithCustomPasteboardDataEnabled(); for (NSString *encodingName in @[ @"utf-8", @"windows-1252", @"bogus-encoding" ]) { [webView synchronouslyLoadHTMLString:[NSString stringWithFormat:@"" "" "" "

Copy me

" "" "", encodingName]]; [webView copy:nil]; [webView waitForNextPresentationUpdate]; markupStringsAndData.append({ readHTMLStringFromPasteboard(), readHTMLDataFromPasteboard() }); } for (auto& [copiedMarkup, copiedData] : markupStringsAndData) { EXPECT_TRUE([copiedMarkup containsString:@""]); NSError *attributedStringConversionError = nil; auto attributedString = adoptNS([[NSAttributedString alloc] initWithData:copiedData.get() options:@{ NSDocumentTypeDocumentOption: NSHTMLTextDocumentType } documentAttributes:nil error:&attributedStringConversionError]); EXPECT_WK_STREQ("我叫謝文昇", [attributedString string]); __block BOOL foundColorAttribute = NO; [attributedString enumerateAttribute:NSForegroundColorAttributeName inRange:NSMakeRange(0, 5) options:0 usingBlock:^(WebCore::CocoaColor *color, NSRange range, BOOL*) { CGFloat redComponent = 0; CGFloat greenComponent = 0; CGFloat blueComponent = 0; [color getRed:&redComponent green:&greenComponent blue:&blueComponent alpha:nil]; EXPECT_EQ(1., redComponent); EXPECT_EQ(0., greenComponent); EXPECT_EQ(0., blueComponent); foundColorAttribute = YES; }]; EXPECT_TRUE(foundColorAttribute); } } #if PLATFORM(MAC) TEST(CopyHTML, ItemTypesWhenCopyingWebContent) { auto webView = createWebViewWithCustomPasteboardDataEnabled(); [webView synchronouslyLoadHTMLString:@"This is some text to copy."]; [webView stringByEvaluatingJavaScript:@"getSelection().selectAllChildren(document.body)"]; [webView copy:nil]; [webView waitForNextPresentationUpdate]; NSArray *items = NSPasteboard.generalPasteboard.pasteboardItems; EXPECT_EQ(1U, items.count); NSArray *types = items.firstObject.types; EXPECT_TRUE([types containsObject:(__bridge NSString *)kUTTypeWebArchive]); EXPECT_TRUE([types containsObject:(__bridge NSString *)NSPasteboardTypeRTF]); EXPECT_TRUE([types containsObject:(__bridge NSString *)NSPasteboardTypeString]); EXPECT_TRUE([types containsObject:(__bridge NSString *)NSPasteboardTypeHTML]); } TEST(CopyHTML, WriteRichTextSelectionToPasteboard) { auto webView = createWebViewWithCustomPasteboardDataEnabled(); [webView synchronouslyLoadHTMLString:@"This is some text to copy."]; [webView stringByEvaluatingJavaScript:@"getSelection().selectAllChildren(document.body)"]; auto pasteboard = [NSPasteboard pasteboardWithUniqueName]; [webView writeSelectionToPasteboard:pasteboard types:@[ (__bridge NSString *)kUTTypeWebArchive ]]; EXPECT_GT([pasteboard dataForType:(__bridge NSString *)kUTTypeWebArchive].length, 0U); } #endif // PLATFORM(MAC) #endif // PLATFORM(COCOA)