Commit 8b2cf556 authored by arthursonzogni's avatar arthursonzogni Committed by Commit Bot

[CSP] Factorize SVGElement & MHTMLElement nonce hiding.

According to:
https://github.com/whatwg/html/pull/2373
html and svg Element are hiding their nonce when there are at least one
Content-Security-Policy defined from an HTTP header.

The two implementation:
- HTMLElement::InsertedInto
- SVGElement::InsertedInto

were hidding the nonce slightly differently. To prevent further
divergence, factorize this implementation into Element::HideNonce() and
call it from both places.

Bug: 1053496
Change-Id: I3cbad88f70c61591bef060d4188c82388e6001d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2078536
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Reviewed-by: default avatarFredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#746837}
parent 4c9f5da8
...@@ -4805,6 +4805,16 @@ Node* Element::InsertAdjacent(const String& where, ...@@ -4805,6 +4805,16 @@ Node* Element::InsertAdjacent(const String& where,
return nullptr; return nullptr;
} }
void Element::HideNonce() {
const AtomicString& nonce_value = FastGetAttribute(html_names::kNonceAttr);
if (nonce_value.IsEmpty())
return;
if (!InActiveDocument())
return;
if (GetDocument().GetContentSecurityPolicy()->HasHeaderDeliveredPolicy())
setAttribute(html_names::kNonceAttr, g_empty_atom);
}
ElementIntersectionObserverData* Element::IntersectionObserverData() const { ElementIntersectionObserverData* Element::IntersectionObserverData() const {
if (HasRareData()) if (HasRareData())
return GetElementRareData()->IntersectionObserverData(); return GetElementRareData()->IntersectionObserverData();
......
...@@ -1013,6 +1013,17 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable { ...@@ -1013,6 +1013,17 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
virtual void ParserDidSetAttributes() {} virtual void ParserDidSetAttributes() {}
// The "nonce" attribute is hidden when:
// 1) The Content-Security-Policy is delivered from the HTTP headers.
// 2) The Element is part of the active document.
// See https://github.com/whatwg/html/pull/2373
//
// This applies to the element of the HTML and SVG namespaces.
//
// This function clears the "nonce" attribute whenever conditions (1) and (2)
// are met.
void HideNonce();
private: private:
void ScrollLayoutBoxBy(const ScrollToOptions*); void ScrollLayoutBoxBy(const ScrollToOptions*);
void ScrollLayoutBoxTo(const ScrollToOptions*); void ScrollLayoutBoxTo(const ScrollToOptions*);
......
...@@ -1213,11 +1213,8 @@ Node::InsertionNotificationRequest HTMLElement::InsertedInto( ...@@ -1213,11 +1213,8 @@ Node::InsertionNotificationRequest HTMLElement::InsertedInto(
// Process the superclass first to ensure that `InActiveDocument()` is // Process the superclass first to ensure that `InActiveDocument()` is
// updated. // updated.
Element::InsertedInto(insertion_point); Element::InsertedInto(insertion_point);
HideNonce();
if (GetDocument().GetContentSecurityPolicy()->HasHeaderDeliveredPolicy() &&
InActiveDocument() && FastHasAttribute(html_names::kNonceAttr)) {
setAttribute(html_names::kNonceAttr, g_empty_atom);
}
if (IsFormAssociatedCustomElement()) if (IsFormAssociatedCustomElement())
EnsureElementInternals().InsertedInto(insertion_point); EnsureElementInternals().InsertedInto(insertion_point);
......
...@@ -296,16 +296,8 @@ AffineTransform SVGElement::CalculateTransform( ...@@ -296,16 +296,8 @@ AffineTransform SVGElement::CalculateTransform(
Node::InsertionNotificationRequest SVGElement::InsertedInto( Node::InsertionNotificationRequest SVGElement::InsertedInto(
ContainerNode& root_parent) { ContainerNode& root_parent) {
Element::InsertedInto(root_parent); Element::InsertedInto(root_parent);
HideNonce();
UpdateRelativeLengthsInformation(); UpdateRelativeLengthsInformation();
const AtomicString& nonce_value = FastGetAttribute(html_names::kNonceAttr);
if (!nonce_value.IsEmpty()) {
setNonce(nonce_value);
if (InActiveDocument() &&
GetDocument().GetContentSecurityPolicy()->HasHeaderDeliveredPolicy()) {
setAttribute(html_names::kNonceAttr, g_empty_atom);
}
}
return kInsertionDone; return kInsertionDone;
} }
......
...@@ -3,30 +3,62 @@ ...@@ -3,30 +3,62 @@
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<div id=log></div> <div id=log></div>
<script> <script>
[["meh", ""], const namespace_url= {
["div", ""], "HTML": "http://www.w3.org/1999/xhtml",
["script", ""], "SVG": "http://www.w3.org/2000/svg",
["meh", "http://www.w3.org/2000/svg"], }
["svg", "http://www.w3.org/2000/svg"], const test_cases = [
["script", "http://www.w3.org/2000/svg"]].forEach(([localName, namespace]) => { ["meh" , "HTML"],
["div" , "HTML"],
["script" , "HTML"],
["meh" , "SVG"],
["svg" , "SVG"],
["script" , "SVG"],
];
test_cases.forEach(([localName, namespace]) => {
test(t => { test(t => {
const element = namespace === "" ? document.createElement(localName) : document.createElementNS(namespace, localName); const element = document.createElementNS(namespace_url[namespace], localName);
t.add_cleanup(() => element.remove()); t.add_cleanup(() => element.remove());
assert_equals(element.nonce, "", "Initial IDL attribute value"); assert_equals(element.nonce, "", "Initial IDL attribute value");
assert_equals(element.getAttribute("nonce"), null, "Initial content attribute");
element.setAttribute("nonce", "x"); element.setAttribute("nonce", "x");
assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set"); assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set");
assert_equals(element.getAttribute("nonce"), "x", "Content attribute is modified after content attribute set"); assert_equals(element.getAttribute("nonce"), "x", "Content attribute is modified after content attribute set");
document.body.appendChild(element); document.body.appendChild(element);
assert_equals(element.nonce, "x", "IDL attribute is unchanged after element insertion"); assert_equals(element.nonce, "x", "IDL attribute is unchanged after element insertion");
assert_equals(element.getAttribute("nonce"), "", "Content attribute is changed after element insertion"); assert_equals(element.getAttribute("nonce"), "", "Content attribute is changed after element insertion");
}, `Basic nonce tests for ${localName} in ${namespace === "" ? "HTML" : "SVG"} namespace`); }, `Basic nonce tests for ${localName} in ${namespace} namespace`);
test(t => { test(t => {
const element = namespace === "" ? document.createElement(localName) : document.createElementNS(namespace, localName); const element = document.createElementNS(namespace_url[namespace], localName);
t.add_cleanup(() => element.remove());
element.setAttribute("nonce", "x"); element.setAttribute("nonce", "x");
assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set"); assert_equals(element.nonce, "x", "IDL attribute is modified after content attribute set");
element.removeAttribute("nonce"); element.removeAttribute("nonce");
assert_equals(element.nonce, "", "IDL attribute is empty after content attribute removal"); assert_equals(element.nonce, "", "IDL attribute is empty after content attribute removal");
}, `Ensure that removal of content attribute does not affect IDL attribute for ${localName} in ${namespace === "" ? "HTML" : "SVG"} namespace`); }, `Ensure that removal of content attribute does not affect IDL attribute for ${localName} in ${namespace} namespace`);
});
test(t => {
const element = document.createElementNS(namespace_url[namespace], localName);
t.add_cleanup(() => element.remove());
assert_equals(element.nonce, "");
assert_equals(element.getAttribute("nonce"), null);
element.setAttribute("nonce", "");
assert_equals(element.nonce, "");
assert_equals(element.getAttribute("nonce"), "");
document.body.appendChild(element);
assert_equals(element.nonce, "");
assert_equals(element.getAttribute("nonce"), "");
element.removeAttribute("nonce");
assert_equals(element.nonce, "");
assert_equals(element.getAttribute("nonce"), null);
}, `Test empty nonces for ${localName} in ${namespace} namespace`);
});
</script> </script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment