| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8" /> |
| <meta |
| http-equiv="Content-Security-Policy" |
| content="require-trusted-types-for 'script';" |
| /> |
| <title> |
| trusted-types (TT): `setAttribute`/`setAttributeNode` for an element |
| adopted from a non-TT realm respects TT's Content-Security-Policy (CSP) |
| </title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| </head> |
| <body> |
| <div id="nonSVGTestElements"> |
| <iframe srcdoc="v"></iframe> |
| <embed src="v" /> |
| <script src="v"></script> |
| <object data="v"></object> |
| <object codebase="v"></object> |
| </div> |
| <svg id="svgTestElements"> |
| <script href="v"></script> |
| <script xlink:href="v"></script> |
| </svg> |
| <script> |
| const passThroughPolicy = trustedTypes.createPolicy("passThrough", { |
| createHTML: (s) => s, |
| }); |
| |
| function runTest(aTestElement) { |
| const testAttr = aTestElement.attributes[0]; |
| |
| async_test( |
| (t) => { |
| const sourceFrame = document.createElement("iframe"); |
| |
| // The markup requires the parent element to ensure the attribute is associated with the |
| // correct namespace. |
| sourceFrame.srcdoc = passThroughPolicy.createHTML( |
| `<!DOCTYPE html> |
| <head> |
| <meta charset="utf-8"> |
| </head> |
| <body> |
| <` + |
| aTestElement.parentElement.localName + |
| `> |
| <` + |
| aTestElement.localName + |
| ` ` + |
| testAttr.name + |
| `="` + |
| testAttr.value + |
| `"> |
| </` + |
| aTestElement.localName + |
| `> |
| </` + |
| aTestElement.parentElement.localName + |
| `> |
| doc without TT CSP. |
| </body>` |
| ); |
| |
| t.add_cleanup(() => { |
| sourceFrame.remove(); |
| }); |
| |
| sourceFrame.addEventListener( |
| "load", |
| t.step_func_done(() => { |
| // A window is a global object which has 1-to-1 mapping to a realm, see the first |
| // note of <https://html.spec.whatwg.org/#realms-settings-objects-global-objects> |
| // and its following paragraph. Here, `sourceElement`'s node document's global |
| // belongs to a non-TT realm. |
| |
| const sourceElement = |
| sourceFrame.contentDocument.body.querySelector( |
| aTestElement.localName |
| ); |
| const sourceAttr = sourceElement.getAttributeNode( |
| testAttr.name |
| ); |
| sourceElement.removeAttributeNode(sourceAttr); |
| |
| document.body.append(sourceElement); |
| // Now `sourceElement`'s node document's global belongs to a TT-realm. |
| |
| assert_throws_js(sourceFrame.contentWindow.TypeError, () => { |
| sourceElement.setAttributeNode(sourceAttr); |
| }); |
| assert_throws_js(sourceFrame.contentWindow.TypeError, () => { |
| sourceElement.setAttributeNS( |
| sourceAttr.namespaceURI, |
| sourceAttr.name, |
| sourceAttr.value |
| ); |
| }); |
| }) |
| ); |
| |
| document.body.append(sourceFrame); |
| }, |
| `setAttribute and setAttributeNode respect the element's node document's global's CSP; |
| Element=${aTestElement.localName}; Parent=${aTestElement.parentElement.localName}; Attribute=${testAttr.name}` |
| ); |
| } |
| |
| for (const testElement of document.querySelectorAll( |
| "#nonSVGTestElements *" |
| )) { |
| runTest(testElement); |
| } |
| |
| for (const testElement of document.querySelectorAll( |
| "#svgTestElements *" |
| )) { |
| runTest(testElement); |
| } |
| </script> |
| </body> |
| </html> |