diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp index 4a3579a9407..bf639be35ca 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp @@ -6,8 +6,15 @@ #include +#include #include #include +#include +#include +#include +#include +#include +#include namespace Web::TrustedTypes { @@ -18,6 +25,53 @@ GC::Ref TrustedTypePolicyFactory::create(JS::Realm& re return realm.create(realm); } +// https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-getattributetype +Optional TrustedTypePolicyFactory::get_attribute_type(String const& tag_name, String& attribute, Optional element_ns, Optional attr_ns) +{ + // 1. Set localName to tagName in ASCII lowercase. + auto const local_name = tag_name.to_ascii_lowercase(); + + // 2. Set attribute to attribute in ASCII lowercase. + attribute = attribute.to_ascii_lowercase(); + + // 3. If elementNs is null or an empty string, set elementNs to HTML namespace. + if (!element_ns.has_value() || element_ns.value().is_empty()) + element_ns = String { Namespace::HTML }; + + // 4. If attrNs is an empty string, set attrNs to null. + if (attr_ns.has_value() && attr_ns.value().is_empty()) + attr_ns.clear(); + + // FIXME: We don't have a method in ElementFactory that can give us the interface name but these are all the cases + // we care about in the table in get_trusted_type_data_for_attribute function + // 5. Let interface be the element interface for localName and elementNs. + String interface; + if (local_name == HTML::TagNames::iframe && element_ns == Namespace::HTML) { + interface = "HTMLIFrameElement"_string; + } else if (local_name == HTML::TagNames::script && element_ns == Namespace::HTML) { + interface = "HTMLScriptElement"_string; + } else if (local_name == SVG::TagNames::script && element_ns == Namespace::SVG) { + interface = "SVGScriptElement"_string; + } else { + interface = "Element"_string; + } + + // 6. Let expectedType be null. + Optional expected_type {}; + + // 7. Set attributeData to the result of Get Trusted Type data for attribute algorithm, + // with the following arguments, interface as element, attribute, attrNs + auto const attribute_data = get_trusted_type_data_for_attribute(interface, attribute, attr_ns); + + // 8. If attributeData is not null, then set expectedType to the interface’s name of the value of the fourth member of attributeData. + if (attribute_data.has_value()) { + expected_type = attribute_data.value().trusted_type; + } + + // 9. Return expectedType. + return expected_type; +} + TrustedTypePolicyFactory::TrustedTypePolicyFactory(JS::Realm& realm) : PlatformObject(realm) { @@ -29,4 +83,40 @@ void TrustedTypePolicyFactory::initialize(JS::Realm& realm) Base::initialize(realm); } +// https://w3c.github.io/trusted-types/dist/spec/#abstract-opdef-get-trusted-type-data-for-attribute +Optional get_trusted_type_data_for_attribute(String const& element, String const& attribute, Optional const& attribute_ns) +{ + // 1. Let data be null. + Optional data {}; + + // 2. If attributeNs is null, and attribute is the name of an event handler content attribute, then: + if (!attribute_ns.has_value()) { +#undef __ENUMERATE +#define __ENUMERATE(attribute_name, event_name) \ + if (attribute == HTML::AttributeNames::attribute_name) { \ + /* 1. Return (Element, null, attribute, TrustedScript, "Element " + attribute). */ \ + return TrustedTypeData { "Element"_string, {}, attribute, "TrustedScript"_string, "Element " #attribute_name ""_string }; \ + } + ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE) + ENUMERATE_WINDOW_EVENT_HANDLERS(__ENUMERATE) +#undef __ENUMERATE + } + + static Vector const table { + { "HTMLIFrameElement"_string, {}, "srcdoc"_string, "TrustedHTML"_string, "HTMLIFrameElement srcdoc"_string }, + { "HTMLScriptElement"_string, {}, "src"_string, "TrustedScriptURL"_string, "HTMLScriptElement src"_string }, + { "SVGScriptElement"_string, {}, "href"_string, "TrustedScriptURL"_string, "SVGScriptElement href"_string }, + { "SVGScriptElement"_string, Namespace::XLink.to_string(), "href"_string, "TrustedScriptURL"_string, "SVGScriptElement href"_string }, + }; + + // 3. Find the row in the following table, where element is in the first column, attributeNs is in the second column, + // and attribute is in the third column. If a matching row is found, set data to that row. + data = table.first_matching([&element, &attribute, &attribute_ns](auto const& row) { + return row.element == element && row.attribute_ns == attribute_ns && row.attribute_local_name == attribute; + }); + + // 4. Return data + return data.copy(); +} + } diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h index 433d74bf65f..fc9e1a72636 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h @@ -21,6 +21,8 @@ public: virtual ~TrustedTypePolicyFactory() override { } + Optional get_attribute_type(String const& tag_name, String& attribute, Optional element_ns, Optional attr_ns); + private: explicit TrustedTypePolicyFactory(JS::Realm&); virtual void initialize(JS::Realm&) override; @@ -28,4 +30,14 @@ private: Vector m_created_policy_names; }; +struct TrustedTypeData { + String element; + Optional attribute_ns; + String attribute_local_name; + String trusted_type; + String sink; +}; + +Optional get_trusted_type_data_for_attribute(String const&, String const&, Optional const&); + } diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.idl b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.idl index 095b1123c14..b5aebb8cab8 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.idl +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.idl @@ -8,7 +8,7 @@ interface TrustedTypePolicyFactory { [FIXME] boolean isScriptURL(any value); [FIXME] readonly attribute TrustedHTML emptyHTML; [FIXME] readonly attribute TrustedScript emptyScript; - [FIXME] DOMString? getAttributeType( + DOMString? getAttributeType( DOMString tagName, DOMString attribute, optional DOMString? elementNs = "",