https://bugs.webkit.org/show_bug.cgi?id=183485
<rdar://problem/
38041984>
Reviewed by Ryosuke Niwa.
Source/WebCore:
After r222656, WebKit now treats raw image data on the pasteboard as files for the purposes of computing
DataTransfer.files and DataTransfer.types. However, this is combined with existing policies that suppress
DataTransfer.getData and DataTransfer.setData when the pasteboard contains files (generalized to copy/paste in
r222688). This means we now don't allow web pages to access "text/plain" in the case where the user copies part
of a table from the native Numbers app since Numbers additionally writes a snapshot of the table to the platform
pasteboard.
This restriction on getData/setData was intended to prevent web pages from extracting users' file paths when
pasting or dropping, so it doesn't make sense to enforce this restriction even when there is only in-memory
image data on the pasteboard. To fix this bug, we make Pasteboard::fileContentState() differentiate between
cases where there are (real) files on the pasteboard, and cases where we've fallen back to treating image data
as files.
Rebaselined existing LayoutTests to match new behavior.
Also covered by 4 new API tests:
- PasteMixedContent.ImageDataAndPlainText
- PasteMixedContent.ImageDataAndPlainTextAndURL
- PasteMixedContent.ImageDataAndPlainTextAndURLAndHTML
- UIPasteboardTests.DataTransferGetDataWhenPastingImageAndText
* dom/DataTransfer.cpp:
(WebCore::DataTransfer::shouldSuppressGetAndSetDataToAvoidExposingFilePaths const):
If custom pasteboard data is enabled, suppress getData and setData if and only if we might actually expose file
paths (see Pasteboard::fileContentState).
(WebCore::DataTransfer::types const):
Only allow "text/html" or "text/uri-list" in the case where there are actual files in the pasteboard. If there's
only image data, add all of the DOM-safe types back into the list of types.
* platform/Pasteboard.h:
* platform/StaticPasteboard.h:
Add an enum type to represent the result of Pasteboard::fileContentState.
- NoFileOrImageData indicates that there was nothing on the pasteboard that could be considered a file
from the point of view of the page.
- InMemoryImage indicates that there are no files on the pasteboard, but there is image data that we consider
to be files, exposed via DataTransfer API.
- MayContainFilePaths indicates that there might be file paths on the pasteboard. This means that the source
has either written file paths to the pasteboard (for example, through NSFilenamesPboardType) or the source
has written image data along with a URL type of some sort that does not match one of the allowed URL schemes
that are safe to expose (currently, these are http-family, data, or blob).
* platform/cocoa/PasteboardCocoa.mm:
(WebCore::Pasteboard::fileContentState):
Refactor to return one of the three enum types described above.
(WebCore::Pasteboard::containsFiles): Deleted.
* platform/gtk/PasteboardGtk.cpp:
(WebCore::Pasteboard::fileContentState):
(WebCore::Pasteboard::containsFiles): Deleted.
* platform/win/PasteboardWin.cpp:
(WebCore::Pasteboard::fileContentState):
(WebCore::Pasteboard::containsFiles): Deleted.
* platform/wpe/PasteboardWPE.cpp:
(WebCore::Pasteboard::fileContentState):
(WebCore::Pasteboard::containsFiles): Deleted.
Adjust for Pasteboard::fileContentState() tweaks.
Tools:
Add new API tests to cover scenarios in which we paste image data alongside text data.
* TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:
(TestWebKitAPI::TEST):
LayoutTests:
Rebaseline some pasteboard-related layout tests, in which we now expose text/plain alongside files that were
written to the DataTransfer by the page itself.
* editing/pasteboard/data-transfer-item-list-add-file-multiple-times-expected.txt:
* editing/pasteboard/data-transfer-item-list-add-file-on-copy-expected.txt:
* editing/pasteboard/data-transfer-item-list-add-file-on-drag-expected.txt:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229503
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2018-03-10 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [macOS] Copying a table from the Numbers app and pasting into iCloud Numbers fails
+ https://bugs.webkit.org/show_bug.cgi?id=183485
+ <rdar://problem/38041984>
+
+ Reviewed by Ryosuke Niwa.
+
+ Rebaseline some pasteboard-related layout tests, in which we now expose text/plain alongside files that were
+ written to the DataTransfer by the page itself.
+
+ * editing/pasteboard/data-transfer-item-list-add-file-multiple-times-expected.txt:
+ * editing/pasteboard/data-transfer-item-list-add-file-on-copy-expected.txt:
+ * editing/pasteboard/data-transfer-item-list-add-file-on-drag-expected.txt:
+
2018-03-09 Chris Dumez <cdumez@apple.com>
inspector/page/frameScheduledNavigation.html has different output with async policy delegates
{
"data": {
"Files": "",
+ "text/plain": "plain text string",
"text/uri-list": "https://webkit.org"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "plain text string",
"text/uri-list": "https://webkit.org"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "plain text string",
"text/uri-list": "https://webkit.org"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "plain text string",
"text/uri-list": "https://webkit.org"
},
"items": [
{
"data": {
"Files": "",
- "text/html": "<strong>some styled text</strong>"
+ "text/html": "<strong>some styled text</strong>",
+ "text/plain": "some plain text"
},
"items": [
{
2. After adding a file of custom type
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
3. After adding the first plain text file
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
4. After removing the last file
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
{
"data": {
"Files": "",
+ "text/plain": "hello world",
"text/html": "<a>goodbye world</a>"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "hello world",
"text/html": "<a>goodbye world</a>"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "hello world",
"text/html": "<a>goodbye world</a>"
},
"items": [
8. After removing the HTML string
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
2. After adding a file of custom type
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
3. After adding the first plain text file
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
4. After removing the last file
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
{
"data": {
"Files": "",
+ "text/plain": "hello world",
"text/html": "<a>goodbye world</a>"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "hello world",
"text/html": "<a>goodbye world</a>"
},
"items": [
{
"data": {
"Files": "",
+ "text/plain": "hello world",
"text/html": "<a>goodbye world</a>"
},
"items": [
8. After removing the HTML string
{
"data": {
- "Files": ""
+ "Files": "",
+ "text/plain": "hello world"
},
"items": [
{
+2018-03-10 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [macOS] Copying a table from the Numbers app and pasting into iCloud Numbers fails
+ https://bugs.webkit.org/show_bug.cgi?id=183485
+ <rdar://problem/38041984>
+
+ Reviewed by Ryosuke Niwa.
+
+ After r222656, WebKit now treats raw image data on the pasteboard as files for the purposes of computing
+ DataTransfer.files and DataTransfer.types. However, this is combined with existing policies that suppress
+ DataTransfer.getData and DataTransfer.setData when the pasteboard contains files (generalized to copy/paste in
+ r222688). This means we now don't allow web pages to access "text/plain" in the case where the user copies part
+ of a table from the native Numbers app since Numbers additionally writes a snapshot of the table to the platform
+ pasteboard.
+
+ This restriction on getData/setData was intended to prevent web pages from extracting users' file paths when
+ pasting or dropping, so it doesn't make sense to enforce this restriction even when there is only in-memory
+ image data on the pasteboard. To fix this bug, we make Pasteboard::fileContentState() differentiate between
+ cases where there are (real) files on the pasteboard, and cases where we've fallen back to treating image data
+ as files.
+
+ Rebaselined existing LayoutTests to match new behavior.
+ Also covered by 4 new API tests:
+ - PasteMixedContent.ImageDataAndPlainText
+ - PasteMixedContent.ImageDataAndPlainTextAndURL
+ - PasteMixedContent.ImageDataAndPlainTextAndURLAndHTML
+ - UIPasteboardTests.DataTransferGetDataWhenPastingImageAndText
+
+ * dom/DataTransfer.cpp:
+ (WebCore::DataTransfer::shouldSuppressGetAndSetDataToAvoidExposingFilePaths const):
+
+ If custom pasteboard data is enabled, suppress getData and setData if and only if we might actually expose file
+ paths (see Pasteboard::fileContentState).
+
+ (WebCore::DataTransfer::types const):
+
+ Only allow "text/html" or "text/uri-list" in the case where there are actual files in the pasteboard. If there's
+ only image data, add all of the DOM-safe types back into the list of types.
+
+ * platform/Pasteboard.h:
+ * platform/StaticPasteboard.h:
+
+ Add an enum type to represent the result of Pasteboard::fileContentState.
+ - NoFileOrImageData indicates that there was nothing on the pasteboard that could be considered a file
+ from the point of view of the page.
+ - InMemoryImage indicates that there are no files on the pasteboard, but there is image data that we consider
+ to be files, exposed via DataTransfer API.
+ - MayContainFilePaths indicates that there might be file paths on the pasteboard. This means that the source
+ has either written file paths to the pasteboard (for example, through NSFilenamesPboardType) or the source
+ has written image data along with a URL type of some sort that does not match one of the allowed URL schemes
+ that are safe to expose (currently, these are http-family, data, or blob).
+
+ * platform/cocoa/PasteboardCocoa.mm:
+ (WebCore::Pasteboard::fileContentState):
+
+ Refactor to return one of the three enum types described above.
+
+ (WebCore::Pasteboard::containsFiles): Deleted.
+ * platform/gtk/PasteboardGtk.cpp:
+ (WebCore::Pasteboard::fileContentState):
+ (WebCore::Pasteboard::containsFiles): Deleted.
+ * platform/win/PasteboardWin.cpp:
+ (WebCore::Pasteboard::fileContentState):
+ (WebCore::Pasteboard::containsFiles): Deleted.
+ * platform/wpe/PasteboardWPE.cpp:
+ (WebCore::Pasteboard::fileContentState):
+ (WebCore::Pasteboard::containsFiles): Deleted.
+
+ Adjust for Pasteboard::fileContentState() tweaks.
+
2018-03-09 Chris Fleizach <cfleizach@apple.com>
AX: WebKit seems to be running spell checker even on non-editable content text
{
if (!forFileDrag() && !RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled())
return false;
- return m_pasteboard->containsFiles();
+ return m_pasteboard->fileContentState() == Pasteboard::FileContentState::MayContainFilePaths;
}
void DataTransfer::setData(const String& type, const String& data)
if (!RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
auto types = m_pasteboard->typesForLegacyUnsafeBindings();
ASSERT(!types.contains("Files"));
- if (m_pasteboard->containsFiles() && addFilesType == AddFilesType::Yes)
+ if (m_pasteboard->fileContentState() != Pasteboard::FileContentState::NoFileOrImageData && addFilesType == AddFilesType::Yes)
types.append("Files");
return types;
}
return item->isFile();
});
- if (hasFileBackedItem || m_pasteboard->containsFiles()) {
+ auto fileContentState = m_pasteboard->fileContentState();
+ if (hasFileBackedItem || fileContentState != Pasteboard::FileContentState::NoFileOrImageData) {
Vector<String> types;
if (addFilesType == AddFilesType::Yes)
types.append(ASCIILiteral("Files"));
+
+ if (fileContentState != Pasteboard::FileContentState::MayContainFilePaths) {
+ types.appendVector(WTFMove(safeTypes));
+ return types;
+ }
+
if (safeTypes.contains("text/uri-list"))
types.append(ASCIILiteral("text/uri-list"));
if (safeTypes.contains("text/html") && RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled())
virtual WEBCORE_EXPORT void writeCustomData(const PasteboardCustomData&);
- virtual WEBCORE_EXPORT bool containsFiles();
+ enum class FileContentState { NoFileOrImageData, InMemoryImage, MayContainFilePaths };
+ virtual WEBCORE_EXPORT FileContentState fileContentState();
virtual WEBCORE_EXPORT bool canSmartReplace();
virtual WEBCORE_EXPORT void writeMarkup(const String& markup);
void writeCustomData(const PasteboardCustomData&) final { }
- bool containsFiles() final { return false; }
+ Pasteboard::FileContentState fileContentState() final { return FileContentState::NoFileOrImageData; }
bool canSmartReplace() final { return false; }
void writeMarkup(const String&) final { }
return cocoaTypeToImageType(cocoaType) != ImageType::Invalid;
}
-bool Pasteboard::containsFiles()
+Pasteboard::FileContentState Pasteboard::fileContentState()
{
- if (!platformStrategies()->pasteboardStrategy()->getNumberOfFiles(m_pasteboardName)) {
+ bool mayContainFilePaths = platformStrategies()->pasteboardStrategy()->getNumberOfFiles(m_pasteboardName);
+ if (!mayContainFilePaths) {
Vector<String> cocoaTypes;
platformStrategies()->pasteboardStrategy()->getTypes(cocoaTypes, m_pasteboardName);
if (cocoaTypes.findMatching([](const String& cocoaType) { return shouldTreatCocoaTypeAsFile(cocoaType); }) == notFound)
- return false;
+ return FileContentState::NoFileOrImageData;
+
+ bool containsURL = notFound != cocoaTypes.findMatching([] (auto& cocoaType) {
+#if PLATFORM(MAC)
+ if (cocoaType == String(legacyURLPasteboardType()))
+ return true;
+#endif
+ return cocoaType == String(kUTTypeURL);
+ });
+ mayContainFilePaths = containsURL && !Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(readString(ASCIILiteral("text/uri-list")));
}
// Enforce changeCount ourselves for security. We check after reading instead of before to be
// sure it doesn't change between our testing the change count and accessing the data.
if (m_changeCount != platformStrategies()->pasteboardStrategy()->changeCount(m_pasteboardName))
- return false;
+ return FileContentState::NoFileOrImageData;
- return true;
+ // Even when there's only image data in the pasteboard and no file representations, we still run the risk of exposing file paths
+ // to the page if the app has written image data to the pasteboard with a corresponding file path as plain text. An example of
+ // this is copying an image with a local `src` in Safari. To mitigate this, we additionally require that the app has not also
+ // written URLs to the pasteboard, as this would suggest that the plain text data might contain file paths.
+ return mayContainFilePaths ? FileContentState::MayContainFilePaths : FileContentState::InMemoryImage;
}
Vector<String> Pasteboard::typesSafeForBindings(const String& origin)
return { };
}
-bool Pasteboard::containsFiles()
+Pasteboard::FileContentState Pasteboard::fileContentState()
{
readFromClipboard();
- return !m_selectionData->filenames().isEmpty();
+ return m_selectionData->filenames().isEmpty() ? FileContentState::NoFileOrImageData : FileContentState::MayContainFilePaths;
}
void Pasteboard::writeMarkup(const String&)
unsigned count { 0 };
};
-bool Pasteboard::containsFiles()
+Pasteboard::FileContentState Pasteboard::fileContentState()
{
// FIXME: This implementation can be slightly more efficient by avoiding calls to DragQueryFileW.
PasteboardFileCounter reader;
read(reader);
- return reader.count;
+ return reader.count ? FileContentState::MayContainFilePaths : FileContentState::NoFileOrImageData;
}
void Pasteboard::read(PasteboardFileReader& reader)
platformStrategies()->pasteboardStrategy()->writeToPasteboard(content);
}
-bool Pasteboard::containsFiles()
+Pasteboard::FileContentState Pasteboard::fileContentState()
{
notImplemented();
- return false;
+ return FileContentState::NoFileOrImageData;
}
bool Pasteboard::canSmartReplace()
+2018-03-10 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ [macOS] Copying a table from the Numbers app and pasting into iCloud Numbers fails
+ https://bugs.webkit.org/show_bug.cgi?id=183485
+ <rdar://problem/38041984>
+
+ Reviewed by Ryosuke Niwa.
+
+ Add new API tests to cover scenarios in which we paste image data alongside text data.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/PasteMixedContent.mm:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:
+ (TestWebKitAPI::TEST):
+
2018-03-09 Zalan Bujtas <zalan@apple.com>
[LayoutReloaded] Initial commit -block formatting context.
EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"rawHTMLData.textContent"] containsString:@"script"]);
}
+TEST(PasteMixedContent, ImageDataAndPlainText)
+{
+ auto webView = setUpWebView();
+ writeTypesAndDataToPasteboard(NSPasteboardTypeString, @"Hello world", NSPasteboardTypePNG, [NSData dataWithContentsOfFile:imagePath()], nil);
+ [webView paste:nil];
+
+ EXPECT_WK_STREQ("Files, text/plain", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
+ EXPECT_WK_STREQ("(STRING, text/plain), (FILE, image/png)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
+ EXPECT_WK_STREQ("('image.png', image/png)", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
+ EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
+}
+
+TEST(PasteMixedContent, ImageDataAndPlainTextAndURL)
+{
+ auto webView = setUpWebView();
+ writeTypesAndDataToPasteboard(NSPasteboardTypeString, imagePath(), NSURLPboardType, imagePath(), NSPasteboardTypePNG, [NSData dataWithContentsOfFile:imagePath()], nil);
+ [webView paste:nil];
+
+ EXPECT_WK_STREQ("Files", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
+ EXPECT_WK_STREQ("(FILE, image/png)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
+ EXPECT_WK_STREQ("('image.png', image/png)", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
+}
+
+TEST(PasteMixedContent, ImageDataAndPlainTextAndURLAndHTML)
+{
+ auto webView = setUpWebView();
+ writeTypesAndDataToPasteboard(NSPasteboardTypeString, imagePath(), NSURLPboardType, imagePath(), NSPasteboardTypeHTML, markupString(), NSPasteboardTypePNG, [NSData dataWithContentsOfFile:imagePath()], nil);
+ [webView paste:nil];
+
+ EXPECT_WK_STREQ("Files, text/html", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
+ EXPECT_WK_STREQ("(STRING, text/html), (FILE, image/png)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
+ EXPECT_WK_STREQ("('image.png', image/png)", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
+ EXPECT_WK_STREQ("HELLO WORLD", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
+ EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"rawHTMLData.textContent"] containsString:@"script"]);
+}
+
} // namespace TestWebKitAPI
#endif // PLATFORM(MAC) && WK_API_ENABLED
});
}
+TEST(UIPasteboardTests, DataTransferGetDataWhenPastingImageAndText)
+{
+ auto webView = setUpWebViewForPasteboardTests(@"DataTransfer");
+ auto copiedText = retainPtr(@"Apple Inc.");
+ auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+ [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypePNG visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[] (DataLoadCompletionBlock completionHandler) -> NSProgress * {
+ completionHandler([NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"icon" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"]], nil);
+ return nil;
+ }];
+ [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[copiedText] (DataLoadCompletionBlock completionHandler) -> NSProgress * {
+ completionHandler([copiedText dataUsingEncoding:NSUTF8StringEncoding], nil);
+ return nil;
+ }];
+ [UIPasteboard generalPasteboard].itemProviders = @[ itemProvider.get() ];
+ [webView paste:nil];
+
+ EXPECT_WK_STREQ("Files, text/plain", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
+ EXPECT_WK_STREQ("(STRING, text/plain), (FILE, image/png)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
+ EXPECT_WK_STREQ("('image.png', image/png)", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
+ EXPECT_WK_STREQ("Apple Inc.", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
+}
+
TEST(UIPasteboardTests, DataTransferSetDataCannotWritePlatformTypes)
{
auto webView = setUpWebViewForPasteboardTests(@"dump-datatransfer-types");