LibWeb: Implement HTMLOrSVGElement.nonce
There are two FIXMEs remaining that depend on a functional PolicyContainer, which we ignore for now and always behave like a CSP is set.
This commit is contained in:
parent
8dcab69779
commit
84fe8d675b
Notes:
github-actions[bot]
2024-10-31 09:47:17 +00:00
Author: https://github.com/gmta Commit: https://github.com/LadybirdBrowser/ladybird/commit/84fe8d675b2 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2036 Reviewed-by: https://github.com/tcl3
12 changed files with 174 additions and 7 deletions
Tests/LibWeb/Text
Userland/Libraries/LibWeb
11
Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt
Normal file
11
Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt
Normal file
|
@ -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;
|
31
Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html
Normal file
31
Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const printNonce = (elm) => println(`nonce: "${elm.nonce}" attribute: ${elm.getAttribute('nonce')};`);
|
||||
|
||||
println('generic IDL and attribute interaction');
|
||||
const s1 = document.createElement('script');
|
||||
printNonce(s1);
|
||||
s1.nonce = '123';
|
||||
printNonce(s1);
|
||||
s1.setAttribute('nonce', '456');
|
||||
printNonce(s1);
|
||||
s1.nonce = null;
|
||||
printNonce(s1);
|
||||
|
||||
println('insertion');
|
||||
const s2 = document.createElement('script');
|
||||
s2.setAttribute('nonce', 'foo');
|
||||
printNonce(s2);
|
||||
document.body.appendChild(s2);
|
||||
printNonce(s2);
|
||||
|
||||
println('cloning');
|
||||
const s3 = document.createElement('script');
|
||||
s3.setAttribute('nonce', 'bar');
|
||||
printNonce(s3);
|
||||
const cs3 = s3.cloneNode();
|
||||
printNonce(cs3);
|
||||
});
|
||||
</script>
|
|
@ -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) \
|
||||
|
|
|
@ -576,6 +576,25 @@ void HTMLElement::attribute_changed(FlyString const& name, Optional<String> cons
|
|||
#undef __ENUMERATE
|
||||
}
|
||||
|
||||
void HTMLElement::attribute_change_steps(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_)
|
||||
{
|
||||
Base::attribute_change_steps(local_name, old_value, value, namespace_);
|
||||
HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> 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)
|
||||
{
|
||||
|
|
|
@ -82,6 +82,9 @@ protected:
|
|||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override;
|
||||
virtual void attribute_change_steps(FlyString const&, Optional<String> const&, Optional<String> const&, Optional<FlyString> const&) override;
|
||||
virtual WebIDL::ExceptionOr<void> cloned(DOM::Node&, bool) override;
|
||||
virtual void inserted() override;
|
||||
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
|
|
|
@ -56,6 +56,61 @@ void HTMLOrSVGElement<ElementBase>::blur()
|
|||
// User agents may selectively or uniformly ignore calls to this method for usability reasons.
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/#dom-noncedelement-nonce
|
||||
template<typename ElementBase>
|
||||
void HTMLOrSVGElement<ElementBase>::attribute_change_steps(FlyString const& local_name, Optional<String> const&, Optional<String> const& value, Optional<FlyString> 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<typename ElementBase>
|
||||
WebIDL::ExceptionOr<void> HTMLOrSVGElement<ElementBase>::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<ElementBase&>(copy).m_cryptographic_nonce = m_cryptographic_nonce;
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/#dom-noncedelement-nonce
|
||||
template<typename ElementBase>
|
||||
void HTMLOrSVGElement<ElementBase>::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<ElementBase*>(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<typename ElementBase>
|
||||
void HTMLOrSVGElement<ElementBase>::visit_edges(JS::Cell::Visitor& visitor)
|
||||
{
|
||||
|
|
|
@ -17,15 +17,25 @@ class HTMLOrSVGElement {
|
|||
public:
|
||||
[[nodiscard]] JS::NonnullGCPtr<DOMStringMap> 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<String> const&, Optional<String> const&, Optional<FlyString> const&);
|
||||
WebIDL::ExceptionOr<void> 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<DOMStringMap> 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 };
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -20,6 +20,25 @@ MathMLElement::MathMLElement(DOM::Document& document, DOM::QualifiedName qualifi
|
|||
{
|
||||
}
|
||||
|
||||
void MathMLElement::attribute_change_steps(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_)
|
||||
{
|
||||
Base::attribute_change_steps(local_name, old_value, value, namespace_);
|
||||
HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> 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);
|
||||
|
|
|
@ -24,6 +24,9 @@ public:
|
|||
virtual Optional<ARIA::Role> default_role() const override;
|
||||
|
||||
protected:
|
||||
virtual void attribute_change_steps(FlyString const&, Optional<String> const&, Optional<String> const&, Optional<FlyString> const&) override;
|
||||
virtual WebIDL::ExceptionOr<void> cloned(DOM::Node&, bool) override;
|
||||
virtual void inserted() override;
|
||||
virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -42,9 +42,23 @@ void SVGElement::attribute_changed(FlyString const& name, Optional<String> const
|
|||
update_use_elements_that_reference_this();
|
||||
}
|
||||
|
||||
void SVGElement::attribute_change_steps(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_)
|
||||
{
|
||||
Base::attribute_change_steps(local_name, old_value, value, namespace_);
|
||||
HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> 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();
|
||||
}
|
||||
|
|
|
@ -22,12 +22,6 @@ class SVGElement
|
|||
public:
|
||||
virtual bool requires_svg_container() const override { return true; }
|
||||
|
||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override;
|
||||
|
||||
virtual void children_changed() override;
|
||||
virtual void inserted() override;
|
||||
virtual void removed_from(Node*) override;
|
||||
|
||||
JS::NonnullGCPtr<SVGAnimatedString> class_name();
|
||||
JS::GCPtr<SVGSVGElement> 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<String> const& old_value, Optional<String> const& value) override;
|
||||
virtual void attribute_change_steps(FlyString const&, Optional<String> const&, Optional<String> const&, Optional<FlyString> const&) override;
|
||||
virtual WebIDL::ExceptionOr<void> 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();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue