diff --git a/Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt b/Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt new file mode 100644 index 00000000000..27b0a1735e0 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt @@ -0,0 +1,11 @@ +generic IDL and attribute interaction +nonce: "" attribute: null; +nonce: "123" attribute: null; +nonce: "456" attribute: 456; +nonce: "null" attribute: 456; +insertion +nonce: "foo" attribute: foo; +nonce: "foo" attribute: ; +cloning +nonce: "bar" attribute: bar; +nonce: "bar" attribute: bar; diff --git a/Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html b/Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html new file mode 100644 index 00000000000..b7fcd23c653 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html @@ -0,0 +1,31 @@ + + + diff --git a/Userland/Libraries/LibWeb/HTML/AttributeNames.h b/Userland/Libraries/LibWeb/HTML/AttributeNames.h index 2423b8b6fcd..0f2544f633c 100644 --- a/Userland/Libraries/LibWeb/HTML/AttributeNames.h +++ b/Userland/Libraries/LibWeb/HTML/AttributeNames.h @@ -119,6 +119,7 @@ namespace AttributeNames { __ENUMERATE_HTML_ATTRIBUTE(name) \ __ENUMERATE_HTML_ATTRIBUTE(nohref) \ __ENUMERATE_HTML_ATTRIBUTE(nomodule) \ + __ENUMERATE_HTML_ATTRIBUTE(nonce) \ __ENUMERATE_HTML_ATTRIBUTE(noresize) \ __ENUMERATE_HTML_ATTRIBUTE(noshade) \ __ENUMERATE_HTML_ATTRIBUTE(novalidate) \ diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp index 9ec1f18b66e..271d53a7102 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -576,6 +576,25 @@ void HTMLElement::attribute_changed(FlyString const& name, Optional cons #undef __ENUMERATE } +void HTMLElement::attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_) +{ + Base::attribute_change_steps(local_name, old_value, value, namespace_); + HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_); +} + +WebIDL::ExceptionOr HTMLElement::cloned(Web::DOM::Node& copy, bool clone_children) +{ + TRY(Base::cloned(copy, clone_children)); + TRY(HTMLOrSVGElement::cloned(copy, clone_children)); + return {}; +} + +void HTMLElement::inserted() +{ + Base::inserted(); + HTMLOrSVGElement::inserted(); +} + // https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-synthetic-pointer-event bool HTMLElement::fire_a_synthetic_pointer_event(FlyString const& type, DOM::Element& target, bool not_trusted) { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.h b/Userland/Libraries/LibWeb/HTML/HTMLElement.h index ccb22ffe064..92f7f9eae0c 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.h @@ -82,6 +82,9 @@ protected: virtual void initialize(JS::Realm&) override; virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value) override; + virtual void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&) override; + virtual WebIDL::ExceptionOr cloned(DOM::Node&, bool) override; + virtual void inserted() override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp index 0072ce790c3..80f0d7a9eff 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp @@ -56,6 +56,61 @@ void HTMLOrSVGElement::blur() // User agents may selectively or uniformly ignore calls to this method for usability reasons. } +// https://html.spec.whatwg.org/#dom-noncedelement-nonce +template +void HTMLOrSVGElement::attribute_change_steps(FlyString const& local_name, Optional const&, Optional const& value, Optional const& namespace_) +{ + // 1. If element does not include HTMLOrSVGElement, then return. + // 2. If localName is not nonce or namespace is not null, then return. + if (local_name != HTML::AttributeNames::nonce || namespace_.has_value()) + return; + + // 3. If value is null, then set element's [[CryptographicNonce]] to the empty string. + if (!value.has_value()) { + m_cryptographic_nonce = {}; + } + + // 4. Otherwise, set element's [[CryptographicNonce]] to value. + else { + m_cryptographic_nonce = value.value(); + } +} + +// https://html.spec.whatwg.org/#dom-noncedelement-nonce +template +WebIDL::ExceptionOr HTMLOrSVGElement::cloned(DOM::Node& copy, bool) +{ + // The cloning steps for elements that include HTMLOrSVGElement must set the + // [[CryptographicNonce]] slot on the copy to the value of the slot on the element being cloned. + static_cast(copy).m_cryptographic_nonce = m_cryptographic_nonce; + return {}; +} + +// https://html.spec.whatwg.org/#dom-noncedelement-nonce +template +void HTMLOrSVGElement::inserted() +{ + // Whenever an element including HTMLOrSVGElement becomes browsing-context connected, the user + // agent must execute the following steps on the element: + DOM::Element& element = *static_cast(this); + + // FIXME: 1. Let CSP list be element's shadow-including root's policy container's CSP list. + [[maybe_unused]] auto policy_container = element.shadow_including_root().document().policy_container(); + + // FIXME: 2. If CSP list contains a header-delivered Content Security Policy, and element has a + // nonce content attribute attr whose value is not the empty string, then: + if (true && element.has_attribute(HTML::AttributeNames::nonce)) { + // 2.1. Let nonce be element's [[CryptographicNonce]]. + auto nonce = m_cryptographic_nonce; + + // 2.2. Set an attribute value for element using "nonce" and the empty string. + element.set_attribute_value(HTML::AttributeNames::nonce, {}); + + // 2.3. Set element's [[CryptographicNonce]] to nonce. + m_cryptographic_nonce = nonce; + } +} + template void HTMLOrSVGElement::visit_edges(JS::Cell::Visitor& visitor) { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h index 9080ac78433..da3495fbc15 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h @@ -17,15 +17,25 @@ class HTMLOrSVGElement { public: [[nodiscard]] JS::NonnullGCPtr dataset(); + // https://html.spec.whatwg.org/#dom-noncedelement-nonce + String const& nonce() { return m_cryptographic_nonce; } + void set_nonce(String const& nonce) { m_cryptographic_nonce = nonce; } + void focus(); void blur(); protected: + void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&); + WebIDL::ExceptionOr cloned(DOM::Node&, bool); + void inserted(); void visit_edges(JS::Cell::Visitor&); // https://html.spec.whatwg.org/multipage/dom.html#dom-dataset-dev JS::GCPtr m_dataset; + // https://html.spec.whatwg.org/#cryptographicnonce + String m_cryptographic_nonce; + // https://html.spec.whatwg.org/multipage/interaction.html#locked-for-focus bool m_locked_for_focus { false }; }; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl index ed719ceef04..88c4b22c5ad 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl +++ b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl @@ -1,7 +1,7 @@ // https://html.spec.whatwg.org/#htmlorsvgelement interface mixin HTMLOrSVGElement { [SameObject] readonly attribute DOMStringMap dataset; - [FIXME] attribute DOMString nonce; // intentionally no [CEReactions] + attribute DOMString nonce; // intentionally no [CEReactions] [CEReactions, Reflect] attribute boolean autofocus; [CEReactions] attribute long tabIndex; diff --git a/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp b/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp index 400c805d011..e5294616cc1 100644 --- a/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp +++ b/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp @@ -20,6 +20,25 @@ MathMLElement::MathMLElement(DOM::Document& document, DOM::QualifiedName qualifi { } +void MathMLElement::attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_) +{ + Base::attribute_change_steps(local_name, old_value, value, namespace_); + HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_); +} + +WebIDL::ExceptionOr MathMLElement::cloned(DOM::Node& node, bool clone_children) +{ + TRY(Base::cloned(node, clone_children)); + TRY(HTMLOrSVGElement::cloned(node, clone_children)); + return {}; +} + +void MathMLElement::inserted() +{ + Base::inserted(); + HTMLOrSVGElement::inserted(); +} + void MathMLElement::initialize(JS::Realm& realm) { Base::initialize(realm); diff --git a/Userland/Libraries/LibWeb/MathML/MathMLElement.h b/Userland/Libraries/LibWeb/MathML/MathMLElement.h index d1bdfcdc99e..5fc98f761d8 100644 --- a/Userland/Libraries/LibWeb/MathML/MathMLElement.h +++ b/Userland/Libraries/LibWeb/MathML/MathMLElement.h @@ -24,6 +24,9 @@ public: virtual Optional default_role() const override; protected: + virtual void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&) override; + virtual WebIDL::ExceptionOr cloned(DOM::Node&, bool) override; + virtual void inserted() override; virtual JS::GCPtr global_event_handlers_to_event_target(FlyString const&) override { return *this; } private: diff --git a/Userland/Libraries/LibWeb/SVG/SVGElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGElement.cpp index 1f48e883d12..4c2a997a4ee 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGElement.cpp @@ -42,9 +42,23 @@ void SVGElement::attribute_changed(FlyString const& name, Optional const update_use_elements_that_reference_this(); } +void SVGElement::attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_) +{ + Base::attribute_change_steps(local_name, old_value, value, namespace_); + HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_); +} + +WebIDL::ExceptionOr SVGElement::cloned(DOM::Node& copy, bool clone_children) +{ + TRY(Base::cloned(copy, clone_children)); + TRY(HTMLOrSVGElement::cloned(copy, clone_children)); + return {}; +} + void SVGElement::inserted() { Base::inserted(); + HTMLOrSVGElement::inserted(); update_use_elements_that_reference_this(); } diff --git a/Userland/Libraries/LibWeb/SVG/SVGElement.h b/Userland/Libraries/LibWeb/SVG/SVGElement.h index d5c74050109..62791676dc7 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGElement.h @@ -22,12 +22,6 @@ class SVGElement public: virtual bool requires_svg_container() const override { return true; } - virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value) override; - - virtual void children_changed() override; - virtual void inserted() override; - virtual void removed_from(Node*) override; - JS::NonnullGCPtr class_name(); JS::GCPtr owner_svg_element(); @@ -37,6 +31,13 @@ protected: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; + virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value) override; + virtual void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&) override; + virtual WebIDL::ExceptionOr cloned(DOM::Node&, bool) override; + virtual void children_changed() override; + virtual void inserted() override; + virtual void removed_from(Node*) override; + void update_use_elements_that_reference_this(); void remove_from_use_element_that_reference_this();