From 7e336260601d51af563d8cc6a6dc5119763770c9 Mon Sep 17 00:00:00 2001 From: Anupam Snigdha Date: Wed, 1 Jun 2022 10:05:53 -0700 Subject: [PATCH] [Clipboard API] Clipboard Web Custom Formats implementation. This patch addresses the changes proposed by the EditingWG[1] and agreed upon by all browser vendors. We are removing the `unsanitized` option, and instead, adding custom format support for MIME types that have "web " prefix in them. Added few wpt tests to test these changes. Below is a summary of the changes in this CL: 1. Removed `unsanitized` option from read/write methods. 2. If the custom format doesn't have a "web " prefix, then clipboard read/write fails. 3. Transient user activation is applicable to all supported formats - text/html, text/plain, image/png and web custom formats. 4. There are two "buckets" of clipboard formats. One for the well-known formats and the other for the web custom format. If the author doesn't specify the web format explicitly, then they don't get access to it. This means, we won't write web custom formats for well-known types implicitly if authors have not indicated that during the write call via a "web " prefix (e.g. "web text/html"). Same applies for reading web custom formats for well-known types- if there aren't any formats in the web custom format map, then we won't return any web custom formats i.e. text/html won't be automatically converted into "web text/html". Spec: https://github.com/w3c/clipboard-apis/pull/175 Explainer: https://github.com/w3c/editing/blob/gh-pages/docs/clipboard-pickling/explainer.md i2p: https://groups.google.com/a/chromium.org/g/blink-dev/c/Lo7WBM_v_LY/m/LncCKkXeAwAJ i2s: https://groups.google.com/a/chromium.org/g/blink-dev/c/k2rgX-4Cigc/m/P0RijrpzBAAJ?utm_medium=email&utm_source=footer&pli=1 1. Github issue: https://github.com/w3c/clipboard-apis/issues/165 Bug: 106449 Change-Id: I86aae6a662089efeede2a01ac87cb698e9646df5 --- ...om-formats-write-read.tentative.https.html | 35 +++++++++++-------- .../async-html-script-removal.https.html | 6 +++- ...or-clipboard-read-resource-load.https.html | 4 +++ ...vigator-clipboard-read-sanitize.https.html | 4 +++ ...-promise-write-blobs-read-blobs.https.html | 5 ++- .../async-svg-script-removal.https.html | 4 +++ ...ml-formats-write-read.tentative.https.html | 24 ++++++++----- ...xt-formats-write-read.tentative.https.html | 25 +++++++------ .../async-write-blobs-read-blobs.https.html | 4 +++ .../async-write-html-read-html.https.html | 4 +++ .../async-write-image-read-image.https.html | 6 ++++ .../async-write-svg-read-svg.https.html | 4 +++ .../write-read-on-detached-iframe.https.html | 2 ++ ...ext-readText-on-detached-iframe.https.html | 2 ++ ...bute-cross-origin-tentative.https.sub.html | 7 ++-- ...-policy-attribute-tentative.https.sub.html | 7 ++-- ...licy-cross-origin-tentative.https.sub.html | 7 ++-- ...by-feature-policy.tentative.https.sub.html | 8 +++-- ...by-feature-policy.tentative.https.sub.html | 14 +++++--- ...bute-cross-origin-tentative.https.sub.html | 7 ++-- ...-policy-attribute-tentative.https.sub.html | 7 ++-- ...licy-cross-origin-tentative.https.sub.html | 7 ++-- ...by-feature-policy.tentative.https.sub.html | 8 +++-- ...by-feature-policy.tentative.https.sub.html | 10 +++--- .../permissions/readText-denied.https.html | 3 ++ .../permissions/readText-granted.https.html | 3 ++ .../permissions/writeText-denied.https.html | 3 ++ .../permissions/writeText-granted.https.html | 3 ++ .../async-write-read.https.html | 4 +++ .../async-write-readText.https.html | 4 +++ .../async-writeText-read.https.html | 4 +++ .../async-writeText-readText.https.html | 4 +++ 32 files changed, 171 insertions(+), 68 deletions(-) diff --git a/clipboard-apis/async-custom-formats-write-read.tentative.https.html b/clipboard-apis/async-custom-formats-write-read.tentative.https.html index b6c368f75bc2f29..c91ce0e5c246b06 100644 --- a/clipboard-apis/async-custom-formats-write-read.tentative.https.html +++ b/clipboard-apis/async-custom-formats-write-read.tentative.https.html @@ -14,26 +14,19 @@ promise_test(async t => { await test_driver.set_permission({name: 'clipboard-read'}, 'granted'); await test_driver.set_permission({name: 'clipboard-write'}, 'granted'); - const format1 = 'application/x-custom-format-clipboard-test-format-1'; - const format2 = 'application/x-custom-format-clipboard-test-format-2'; + const format1 = 'web application/x-custom-format-clipboard-test-format-1'; + const format2 = 'web application/x-custom-format-clipboard-test-format-2'; const blobInput1 = new Blob(['input data 1'], {type: format1}); const blobInput2 = new Blob(['input data 2'], {type: format2}); const clipboardItemInput = new ClipboardItem( - {[format1]: blobInput1, [format2]: blobInput2}, - {unsanitized: [format1, format2]}); + {[format1]: blobInput1, [format2]: blobInput2}); await waitForUserActivation(); await navigator.clipboard.write([clipboardItemInput]); - // Items may not be readable on the sanitized clipboard after custom format - // write. - await promise_rejects_dom(t, 'DataError', - navigator.clipboard.read()); - // Items should be readable on a custom format clipboard after custom format // write. await waitForUserActivation(); - const clipboardItems = await navigator.clipboard.read( - {unsanitized: [format1, format2]}); + const clipboardItems = await navigator.clipboard.read(); assert_equals(clipboardItems.length, 1); const clipboardItem = clipboardItems[0]; assert_true(clipboardItem instanceof ClipboardItem); @@ -58,15 +51,29 @@ const customFormatArray = []; const customFormatMap = {}; for (let i = 0; i <= 100; i++) { - customFormatArray.push("CustomFormat" + i); + customFormatArray.push("web text/CustomFormat" + i); const blobInput = new Blob(['input data'], {type: customFormatArray[i]}); customFormatMap[customFormatArray[i]] = blobInput; } - const clipboardItemInput = new ClipboardItem(customFormatMap, - {unsanitized: customFormatArray}); + const clipboardItemInput = new ClipboardItem(customFormatMap); await waitForUserActivation(); await promise_rejects_dom(t, 'NotAllowedError', navigator.clipboard.write([clipboardItemInput])); }, 'navigator.clipboard.write() fails for more than 100 custom formats'); +promise_test(async t => { + await test_driver.set_permission({name: 'clipboard-read'}, 'granted'); + await test_driver.set_permission({name: 'clipboard-write'}, 'granted'); + + const format1 = 'application/x-custom-format-clipboard-test-format-1'; + const format2 = 'application/x-custom-format-clipboard-test-format-2'; + const blobInput1 = new Blob(['input data 1'], {type: format1}); + const blobInput2 = new Blob(['input data 2'], {type: format2}); + const clipboardItemInput = new ClipboardItem( + {[format1]: blobInput1, [format2]: blobInput2}); + await waitForUserActivation(); + await promise_rejects_dom(t, 'NotAllowedError', + navigator.clipboard.write([clipboardItemInput])); +}, 'navigator.clipboard.write() fails for custom formats without web prefix'); + diff --git a/clipboard-apis/async-html-script-removal.https.html b/clipboard-apis/async-html-script-removal.https.html index 90dc44c9db20e31..44c11add855137e 100644 --- a/clipboard-apis/async-html-script-removal.https.html +++ b/clipboard-apis/async-html-script-removal.https.html @@ -4,10 +4,12 @@ Async Clipboard write ([text/html ClipboardItem]) -> readHtml (and remove scripts) tests +Body needed for test_driver.click() + + +Body needed for test_driver.click()

@@ -27,6 +29,7 @@ await test_driver.set_permission({name: 'clipboard-read'}, 'granted'); await test_driver.click(button); + await waitForUserActivation(); const items = await navigator.clipboard.read(); const htmlBlob = await items[0].getType("text/html"); const html = await htmlBlob.text(); @@ -38,3 +41,4 @@ assert_false(loadObserved, 'Should not observe resource loading'); }); + diff --git a/clipboard-apis/async-navigator-clipboard-read-sanitize.https.html b/clipboard-apis/async-navigator-clipboard-read-sanitize.https.html index 9e0ab2ee740f85e..cc1836753478b79 100644 --- a/clipboard-apis/async-navigator-clipboard-read-sanitize.https.html +++ b/clipboard-apis/async-navigator-clipboard-read-sanitize.https.html @@ -7,7 +7,9 @@ + +Body needed for test_driver.click()

@@ -29,6 +31,7 @@ await test_driver.set_permission({name: 'clipboard-read'}, 'granted'); await test_driver.click(button); + await waitForUserActivation(); const items = await navigator.clipboard.read(); const htmlBlob = await items[0].getType("text/html"); const html = await htmlBlob.text(); @@ -42,3 +45,4 @@ assert_false(testFailed); }); + diff --git a/clipboard-apis/async-promise-write-blobs-read-blobs.https.html b/clipboard-apis/async-promise-write-blobs-read-blobs.https.html index e4b93c7c5ffb7c0..12184c92e0777f5 100644 --- a/clipboard-apis/async-promise-write-blobs-read-blobs.https.html +++ b/clipboard-apis/async-promise-write-blobs-read-blobs.https.html @@ -4,10 +4,12 @@ Async Clipboard write blobs -> read blobs with promise tests +Body needed for test_driver.click() + + diff --git a/clipboard-apis/async-unsanitized-plaintext-formats-write-read.tentative.https.html b/clipboard-apis/async-unsanitized-plaintext-formats-write-read.tentative.https.html index f44ed22618e2fd0..1c5638ca0a5faf8 100644 --- a/clipboard-apis/async-unsanitized-plaintext-formats-write-read.tentative.https.html +++ b/clipboard-apis/async-unsanitized-plaintext-formats-write-read.tentative.https.html @@ -18,32 +18,35 @@ await test_driver.set_permission({name: 'clipboard-write'}, 'granted'); const dataToWrite = 'Test text.'; - const format = 'text/plain'; + const format1 = 'web text/plain'; + const format2 = 'text/plain'; - const blobInput = new Blob([dataToWrite], {type: format}); + const blobInput1 = new Blob([dataToWrite], {type: format1}); + const blobInput2 = new Blob([dataToWrite], {type: format2}); // Blob types are automatically converted to lower-case. - assert_equals(blobInput.type, format.toLowerCase()); + assert_equals(blobInput1.type, format1.toLowerCase()); + assert_equals(blobInput2.type, format2.toLowerCase()); const clipboardItemInput = new ClipboardItem( - {[format]: blobInput}, {unsanitized: [format]}); + {[format1]: blobInput1, [format2]: blobInput2}); await waitForUserActivation(); await navigator.clipboard.write([clipboardItemInput]); // Items should be readable on a system clipboard after custom format write. await waitForUserActivation(); - const clipboardItems = await navigator.clipboard.read( - {unsanitized: [format]}); + const clipboardItems = await navigator.clipboard.read(); assert_equals(clipboardItems.length, 1); const clipboardItem = clipboardItems[0]; assert_true(clipboardItem instanceof ClipboardItem); - const blobOutput = await clipboardItem.getType(format); - assert_equals(blobOutput.type, format); - const data = await (new Response(blobOutput)).text(); - assert_equals(data, dataToWrite); + const blobOutput1 = await clipboardItem.getType(format1); + assert_equals(blobOutput1.type, format1); + const data1 = await (new Response(blobOutput1)).text(); + assert_equals(data1, dataToWrite); // These examples use native text formats, so these formats should be // accessible as text. + await waitForUserActivation(); const textOutput = await navigator.clipboard.readText(); assert_equals(textOutput, dataToWrite); -}, 'Verify write and read unsanitized content to the clipboard given standard format as input'); +}, 'Verify write and read unsanitized content to the clipboard given standard and custom formats as input'); diff --git a/clipboard-apis/async-write-blobs-read-blobs.https.html b/clipboard-apis/async-write-blobs-read-blobs.https.html index 50d23a9c3625d52..8bec558b2b2de8a 100644 --- a/clipboard-apis/async-write-blobs-read-blobs.https.html +++ b/clipboard-apis/async-write-blobs-read-blobs.https.html @@ -4,10 +4,12 @@ Async Clipboard write blobs -> read blobs tests +Body needed for test_driver.click() + + + +Body needed for test_driver.click()

The bottom image should display the same image as the top image.

Original Image:

@@ -47,7 +49,9 @@ assert_equals(blobInput.type, 'image/png'); const clipboardItemInput = new ClipboardItem({'image/png' : blobInput}); + await waitForUserActivation(); await navigator.clipboard.write([clipboardItemInput]); + await waitForUserActivation(); const clipboardItems = await navigator.clipboard.read(); assert_equals(clipboardItems.length, 1); @@ -73,7 +77,9 @@ const invalidPngBlob = new Blob(['this text is not a valid png image'], {type: 'image/png'}); const clipboardItemInput = new ClipboardItem({'image/png' : invalidPngBlob}); + await waitForUserActivation(); await promise_rejects_dom(t, 'DataError', navigator.clipboard.write([clipboardItemInput])); }, 'Verify write error on malformed data [image/png ClipboardItem]'); + diff --git a/clipboard-apis/async-write-svg-read-svg.https.html b/clipboard-apis/async-write-svg-read-svg.https.html index 19c91597c111ee2..42f6c547b297994 100644 --- a/clipboard-apis/async-write-svg-read-svg.https.html +++ b/clipboard-apis/async-write-svg-read-svg.https.html @@ -4,10 +4,12 @@ Async Clipboard write ([image/svg+xml ClipboardItem]) -> read and write svg tests +Body needed for test_driver.click() + + + + - diff --git a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-attribute-tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-attribute-tentative.https.sub.html index 15d268426163727..e812854b4c75053 100644 --- a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-attribute-tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-attribute-tentative.https.sub.html @@ -1,17 +1,19 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-cross-origin-tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-cross-origin-tentative.https.sub.html index 1b6f4929a19deaf..c371ea3b41cb2e6 100644 --- a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-cross-origin-tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy-cross-origin-tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy.tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy.tentative.https.sub.html index f8c5bcb129f9324..552183cc67d461a 100644 --- a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy.tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-by-feature-policy.tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html index 47aa6511ec599be..17dc3628a772204 100644 --- a/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-read/clipboard-read-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-cross-origin-tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-cross-origin-tentative.https.sub.html index c931bbbb89f32f8..e669c8fec4910dc 100644 --- a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-cross-origin-tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-cross-origin-tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-tentative.https.sub.html index a2858c638e6c05f..b57dfe3dd2888dc 100644 --- a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-attribute-tentative.https.sub.html @@ -1,17 +1,19 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-cross-origin-tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-cross-origin-tentative.https.sub.html index 0f3164d9b02a13f..6e7029cc789a63e 100644 --- a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-cross-origin-tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy-cross-origin-tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy.tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy.tentative.https.sub.html index 1c6fc49a056605a..ca97994c617d0ee 100644 --- a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy.tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-by-feature-policy.tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html index 51db5a427d2b414..5615a68ac55af81 100644 --- a/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html +++ b/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html @@ -1,10 +1,11 @@ - +Body needed for test_driver.click() + - diff --git a/clipboard-apis/permissions/readText-denied.https.html b/clipboard-apis/permissions/readText-denied.https.html index 935f520e7de2dd1..010f4ba21b95332 100644 --- a/clipboard-apis/permissions/readText-denied.https.html +++ b/clipboard-apis/permissions/readText-denied.https.html @@ -2,15 +2,18 @@ navigator.clipboard.readText() fails when permission denied +Body needed for test_driver.click() + + \ No newline at end of file diff --git a/clipboard-apis/permissions/writeText-denied.https.html b/clipboard-apis/permissions/writeText-denied.https.html index 4d0530f0bc22177..5fbcab411748e25 100644 --- a/clipboard-apis/permissions/writeText-denied.https.html +++ b/clipboard-apis/permissions/writeText-denied.https.html @@ -2,15 +2,18 @@ navigator.clipboard.writeText() fails when permission denied +Body needed for test_driver.click() + + \ No newline at end of file diff --git a/clipboard-apis/text-write-read/async-write-read.https.html b/clipboard-apis/text-write-read/async-write-read.https.html index a00c5b27a4d65f1..c46e5d431713141 100644 --- a/clipboard-apis/text-write-read/async-write-read.https.html +++ b/clipboard-apis/text-write-read/async-write-read.https.html @@ -5,10 +5,12 @@ read ([text/plain ClipboardItem]) tests +Body needed for test_driver.click() + + + +