1/*
2 * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if WK_API_ENABLED && PLATFORM(COCOA)
29
30#import "PlatformUtilities.h"
31#import "TestWKWebView.h"
32#import <WebCore/LegacyNSPasteboardTypes.h>
33#import <WebKit/WKPreferencesPrivate.h>
34#import <WebKit/WKPreferencesRefPrivate.h>
35#import <WebKit/WKWebViewConfigurationPrivate.h>
36#import <wtf/RetainPtr.h>
37#import <wtf/text/WTFString.h>
38
39#if PLATFORM(IOS)
40#include <MobileCoreServices/MobileCoreServices.h>
41#endif
42
43@interface WKWebView ()
44- (void)paste:(id)sender;
45@end
46
47#if PLATFORM(MAC)
48void writeHTMLToPasteboard(NSString *html)
49{
50 [[NSPasteboard generalPasteboard] declareTypes:@[WebCore::legacyHTMLPasteboardType()] owner:nil];
51 [[NSPasteboard generalPasteboard] setString:html forType:WebCore::legacyHTMLPasteboardType()];
52}
53#else
54void writeHTMLToPasteboard(NSString *html)
55{
56 [[UIPasteboard generalPasteboard] setItems:@[@{ (NSString *)kUTTypeHTML : html}]];
57}
58#endif
59
60static RetainPtr<TestWKWebView> createWebViewWithCustomPasteboardDataSetting(bool enabled)
61{
62 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
63 auto preferences = (WKPreferencesRef)[[webView configuration] preferences];
64 WKPreferencesSetDataTransferItemsEnabled(preferences, true);
65 WKPreferencesSetCustomPasteboardDataEnabled(preferences, enabled);
66 return webView;
67}
68
69TEST(PasteHTML, ExposesHTMLTypeInDataTransfer)
70{
71 auto webView = createWebViewWithCustomPasteboardDataSetting(true);
72 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"];
73
74 writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><p><u>hello</u>, world</p></body></html>");
75 [webView paste:nil];
76
77 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"]);
78 [webView stringByEvaluatingJavaScript:@"editor.innerHTML = clipboardData.values[0]; editor.focus()"];
79 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue);
80 [webView stringByEvaluatingJavaScript:@"getSelection().modify('move', 'forward', 'lineboundary')"];
81 EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue);
82 EXPECT_WK_STREQ("hello, world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
83}
84
85TEST(PasteHTML, SanitizesHTML)
86{
87 auto webView = createWebViewWithCustomPasteboardDataSetting(true);
88 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"];
89
90 writeHTMLToPasteboard(@"<!DOCTYPE html><meta content=\"secret\"><b onmouseover=\"dangerousCode()\">hello</b>"
91 "<!-- secret-->, world<script>dangerousCode()</script>';");
92 [webView paste:nil];
93
94 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue);
95 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue);
96 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue);
97 EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue);
98 EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('dangerousCode')"].boolValue);
99}
100
101TEST(PasteHTML, DoesNotSanitizeHTMLWhenCustomPasteboardDataIsDisabled)
102{
103 auto webView = createWebViewWithCustomPasteboardDataSetting(false);
104 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"];
105
106 writeHTMLToPasteboard(@"<!DOCTYPE html><meta content=\"secret\"><b onmouseover=\"dangerousCode()\">hello</b>"
107 "<!-- secret-->, world<script>dangerousCode()</script>';");
108 [webView paste:nil];
109
110 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue);
111 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue);
112 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue);
113 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue);
114 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('dangerousCode')"].boolValue);
115}
116
117TEST(PasteHTML, StripsHTTPURLs)
118{
119 auto webView = createWebViewWithCustomPasteboardDataSetting(true);
120 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"];
121
122 writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><a alt='hello' href='file:///private/var/folders/secret/files/'>world</a>");
123 [webView paste:nil];
124
125 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue);
126 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue);
127 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue);
128 EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue);
129}
130
131TEST(PasteHTML, DoesNotStripHTTPURLsWhenCustomPasteboardDataIsDisabled)
132{
133 auto webView = createWebViewWithCustomPasteboardDataSetting(false);
134 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"];
135
136 writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><a alt='hello' href='file:///private/var/folders/secret/files/'>world</a>");
137 [webView paste:nil];
138
139 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue);
140 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue);
141 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue);
142 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue);
143}
144
145TEST(PasteHTML, KeepsHTTPURLs)
146{
147 auto webView = createWebViewWithCustomPasteboardDataSetting(true);
148 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"];
149
150 writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><a title='hello' href='https://svn.webkit.org/repository/webkit/trunk/LayoutTests/editing/resources/abe.png'>world</a>");
151 [webView paste:nil];
152
153 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue);
154 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue);
155 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue);
156 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('abe.png')"].boolValue);
157}
158
159#endif // WK_API_ENABLED && PLATFORM(COCOA)