diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 9dc981e42c0..b55d8fa6815 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -56,6 +56,7 @@ set(SOURCES ContentSecurityPolicy/Directives/FrameSourceDirective.cpp ContentSecurityPolicy/Directives/ImageSourceDirective.cpp ContentSecurityPolicy/Directives/KeywordSources.cpp + ContentSecurityPolicy/Directives/KeywordTrustedTypes.cpp ContentSecurityPolicy/Directives/ManifestSourceDirective.cpp ContentSecurityPolicy/Directives/MediaSourceDirective.cpp ContentSecurityPolicy/Directives/Names.cpp diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Directives/KeywordTrustedTypes.cpp b/Libraries/LibWeb/ContentSecurityPolicy/Directives/KeywordTrustedTypes.cpp new file mode 100644 index 00000000000..08d4bd13735 --- /dev/null +++ b/Libraries/LibWeb/ContentSecurityPolicy/Directives/KeywordTrustedTypes.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025, Miguel Sacristán Izcue + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Web::ContentSecurityPolicy::Directives::KeywordTrustedTypes { + +#define __ENUMERATE_KEYWORD_TRUSTED_TYPE(name, value) \ + FlyString name = value##_fly_string; +ENUMERATE_KEYWORD_TRUSTED_TYPES +#undef __ENUMERATE_KEYWORD_TRUSTED_TYPE + +} diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Directives/KeywordTrustedTypes.h b/Libraries/LibWeb/ContentSecurityPolicy/Directives/KeywordTrustedTypes.h new file mode 100644 index 00000000000..a07ad3c38c4 --- /dev/null +++ b/Libraries/LibWeb/ContentSecurityPolicy/Directives/KeywordTrustedTypes.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025, Miguel Sacristán Izcue + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::ContentSecurityPolicy::Directives::KeywordTrustedTypes { + +// https://www.w3.org/TR/trusted-types/#tt-keyword +#define ENUMERATE_KEYWORD_TRUSTED_TYPES \ + __ENUMERATE_KEYWORD_TRUSTED_TYPE(AllowDuplicates, "'allow-duplicates'") \ + __ENUMERATE_KEYWORD_TRUSTED_TYPE(None, "'none'") \ + __ENUMERATE_KEYWORD_TRUSTED_TYPE(WildCard, "*") + +#define __ENUMERATE_KEYWORD_TRUSTED_TYPE(name, value) extern FlyString name; +ENUMERATE_KEYWORD_TRUSTED_TYPES +#undef __ENUMERATE_KEYWORD_TRUSTED_TYPE + +} diff --git a/Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.h b/Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.h index 8022bcfd372..4709d88cb5d 100644 --- a/Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.h +++ b/Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.h @@ -32,6 +32,7 @@ namespace Web::ContentSecurityPolicy::Directives::Names { __ENUMERATE_DIRECTIVE_NAME(StyleSrc, "style-src") \ __ENUMERATE_DIRECTIVE_NAME(StyleSrcElem, "style-src-elem") \ __ENUMERATE_DIRECTIVE_NAME(StyleSrcAttr, "style-src-attr") \ + __ENUMERATE_DIRECTIVE_NAME(TrustedTypes, "trusted-types") \ __ENUMERATE_DIRECTIVE_NAME(WebRTC, "webrtc") \ __ENUMERATE_DIRECTIVE_NAME(WorkerSrc, "worker-src") diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h index 3adc2058d80..78a0a18ffee 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h @@ -25,6 +25,8 @@ class TrustedTypePolicy final : public Bindings::PlatformObject { public: virtual ~TrustedTypePolicy() override = default; + String const& name() const { return m_name; } + private: explicit TrustedTypePolicy(JS::Realm&, String const&, TrustedTypePolicyOptions const&); virtual void initialize(JS::Realm&) override; diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl index b98cb21a107..ed839564a46 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl @@ -1,7 +1,7 @@ // https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy [Exposed=(Window,Worker)] interface TrustedTypePolicy { - [FIXME] readonly attribute DOMString name; + readonly attribute DOMString name; [FIXME] TrustedHTML createHTML(DOMString input, any... arguments); [FIXME] TrustedScript createScript(DOMString input, any... arguments); [FIXME] TrustedScriptURL createScriptURL(DOMString input, any... arguments); diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp index 1e8047143be..c4c325b66c4 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -164,13 +165,12 @@ bool TrustedTypePolicyFactory::is_html(JS::Value value) } // https://w3c.github.io/trusted-types/dist/spec/#create-trusted-type-policy-algorithm -WebIDL::ExceptionOr> TrustedTypePolicyFactory::create_a_trusted_type_policy(String const& policy_name, TrustedTypePolicyOptions const& options, JS::Object&) +WebIDL::ExceptionOr> TrustedTypePolicyFactory::create_a_trusted_type_policy(String const& policy_name, TrustedTypePolicyOptions const& options, JS::Object& global) { auto& realm = this->realm(); - // TODO // 1. Let allowedByCSP be the result of executing Should Trusted Type policy creation be blocked by Content Security Policy? algorithm with global, policyName and factory’s created policy names value. - auto const allowed_by_csp = ContentSecurityPolicy::Directives::Directive::Result::Blocked; + auto const allowed_by_csp = should_trusted_type_policy_be_blocked_by_content_security_policy(global, policy_name, m_created_policy_names); // 2. If allowedByCSP is "Blocked", throw a TypeError and abort further steps. if (allowed_by_csp == ContentSecurityPolicy::Directives::Directive::Result::Blocked) @@ -196,6 +196,68 @@ WebIDL::ExceptionOr> TrustedTypePolicyFactory::create return policy; } +// https://www.w3.org/TR/trusted-types/#should-block-create-policy +ContentSecurityPolicy::Directives::Directive::Result TrustedTypePolicyFactory::should_trusted_type_policy_be_blocked_by_content_security_policy(JS::Object& global, String const& policy_name, Vector const& created_policy_names) +{ + // 1. Let result be "Allowed". + auto result = ContentSecurityPolicy::Directives::Directive::Result::Allowed; + + // 2. For each policy in global’s CSP list: + for (auto const policy : ContentSecurityPolicy::PolicyList::from_object(global)->policies()) { + // 1. Let createViolation be false. + bool create_violation = false; + + // 2. If policy’s directive set does not contain a directive which name is "trusted-types", skip to the next policy. + if (!policy->contains_directive_with_name(ContentSecurityPolicy::Directives::Names::TrustedTypes)) + continue; + + // 3. Let directive be the policy’s directive set’s directive which name is "trusted-types" + auto const directive = policy->get_directive_by_name(ContentSecurityPolicy::Directives::Names::TrustedTypes); + + // 4. If directive’s value only contains a tt-keyword which is a match for a value 'none', set createViolation to true. + if (directive->value().size() == 1 && directive->value().first().equals_ignoring_ascii_case(ContentSecurityPolicy::Directives::KeywordTrustedTypes::None)) + create_violation = true; + + // 5. If createdPolicyNames contains policyName and directive’s value does not contain a tt-keyword which is a match for a value 'allow-duplicates', set createViolation to true. + auto created_policy_names_iterator = created_policy_names.find(policy_name); + if (!created_policy_names_iterator.is_end()) { + auto maybe_allow_duplicates = directive->value().find_if([](auto const& directive_value) { + return directive_value.equals_ignoring_ascii_case(ContentSecurityPolicy::Directives::KeywordTrustedTypes::AllowDuplicates); + }); + if (maybe_allow_duplicates.is_end()) + create_violation = true; + } + + // 6. If directive’s value does not contain a tt-policy-name, which value is policyName, and directive’s value does not contain a tt-wildcard, set createViolation to true. + auto directive_value_iterator = directive->value().find(policy_name); + if (directive_value_iterator.is_end()) { + auto maybe_wild_card = directive->value().find_if([](auto const& directive_value) { + return directive_value.equals_ignoring_ascii_case(ContentSecurityPolicy::Directives::KeywordTrustedTypes::WildCard); + }); + + if (maybe_wild_card.is_end()) + create_violation = true; + } + + // 7. If createViolation is false, skip to the next policy. + if (!create_violation) + continue; + + // FIXME + // 8. Let violation be the result of executing Create a violation object for global, policy, and directive on global, policy and "trusted-types" + // 9. Set violation’s resource to "trusted-types-policy". + // 10. Set violation’s sample to the substring of policyName, containing its first 40 characters. + // 11. Execute Report a violation on violation. + + // 12. If policy’s disposition is "enforce", then set result to "Blocked". + if (policy->disposition() == ContentSecurityPolicy::Policy::Disposition::Enforce) + result = ContentSecurityPolicy::Directives::Directive::Result::Blocked; + } + + // 3. Return result. + return result; +} + // 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) { diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h index 81fb07f6478..618cb9964bb 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace Web::TrustedTypes { @@ -41,6 +42,7 @@ private: virtual void visit_edges(Visitor&) override; WebIDL::ExceptionOr> create_a_trusted_type_policy(String const&, TrustedTypePolicyOptions const&, JS::Object&); + ContentSecurityPolicy::Directives::Directive::Result should_trusted_type_policy_be_blocked_by_content_security_policy(JS::Object&, String const&, Vector const&); // https://w3c.github.io/trusted-types/dist/spec/#trustedtypepolicyfactory-created-policy-names Vector m_created_policy_names;