mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-22 17:29:01 +00:00
LibWeb: Add require-trusted-types-for Directive
This is meant to configure the behaviour of an injection sinks when a string is passed.
This commit is contained in:
parent
2083708897
commit
8df173e1bd
Notes:
github-actions[bot]
2025-09-01 15:21:05 +00:00
Author: https://github.com/tete17
Commit: 8df173e1bd
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5828
Reviewed-by: https://github.com/AtkinsSJ
Reviewed-by: https://github.com/Lubrsi ✅
11 changed files with 218 additions and 31 deletions
|
@ -922,6 +922,7 @@ set(SOURCES
|
|||
SVG/SVGViewElement.cpp
|
||||
SVG/TagNames.cpp
|
||||
TrustedTypes/InjectionSink.cpp
|
||||
TrustedTypes/RequireTrustedTypesForDirective.cpp
|
||||
TrustedTypes/TrustedHTML.cpp
|
||||
TrustedTypes/TrustedScript.cpp
|
||||
TrustedTypes/TrustedScriptURL.cpp
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
// 5. A pre-navigation check, which takes a request, a navigation type string ("form-submission" or "other")
|
||||
// and a policy as arguments, and is executed during § 4.2.4 Should navigation request of type be blocked by
|
||||
// Content Security Policy?. It returns "Allowed" unless otherwise specified.
|
||||
virtual Result pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request const>, NavigationType, GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
virtual Result pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request>, NavigationType, GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directive-navigation-response-check
|
||||
// 6. A navigation response check, which takes a request, a navigation type string ("form-submission" or "other"),
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <LibWeb/ContentSecurityPolicy/Directives/StyleSourceElementDirective.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/WebRTCDirective.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/WorkerSourceDirective.h>
|
||||
#include <LibWeb/TrustedTypes/RequireTrustedTypesForDirective.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
||||
|
@ -78,6 +79,9 @@ GC::Ref<Directive> create_directive(GC::Heap& heap, String name, Vector<String>
|
|||
if (name == Names::ReportUri)
|
||||
return heap.allocate<ReportUriDirective>(move(name), move(value));
|
||||
|
||||
if (name == Names::RequireTrustedTypesFor)
|
||||
return heap.allocate<TrustedTypes::RequireTrustedTypesForDirective>(move(name), move(value));
|
||||
|
||||
if (name == Names::Sandbox)
|
||||
return heap.allocate<SandboxDirective>(move(name), move(value));
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ FormActionDirective::FormActionDirective(String name, Vector<String> value)
|
|||
{
|
||||
}
|
||||
|
||||
Directive::Result FormActionDirective::pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request const> request, NavigationType navigation_type, GC::Ref<Policy const> policy) const
|
||||
Directive::Result FormActionDirective::pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request> request, NavigationType navigation_type, GC::Ref<Policy const> policy) const
|
||||
{
|
||||
// 1. Assert: policy is unused in this algorithm.
|
||||
// FIXME: File spec issue, because this is not the case. The policy is required to resolve 'self'.
|
||||
|
|
|
@ -18,7 +18,7 @@ class FormActionDirective final : public Directive {
|
|||
public:
|
||||
virtual ~FormActionDirective() = default;
|
||||
|
||||
virtual Result pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request const>, NavigationType, GC::Ref<Policy const>) const override;
|
||||
virtual Result pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request>, NavigationType, GC::Ref<Policy const>) const override;
|
||||
|
||||
private:
|
||||
FormActionDirective(String name, Vector<String> value);
|
||||
|
|
|
@ -10,30 +10,31 @@
|
|||
|
||||
namespace Web::ContentSecurityPolicy::Directives::Names {
|
||||
|
||||
#define ENUMERATE_DIRECTIVE_NAMES \
|
||||
__ENUMERATE_DIRECTIVE_NAME(BaseUri, "base-uri") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ChildSrc, "child-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ConnectSrc, "connect-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(DefaultSrc, "default-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FontSrc, "font-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FormAction, "form-action") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FrameAncestors, "frame-ancestors") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FrameSrc, "frame-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ImgSrc, "img-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ManifestSrc, "manifest-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(MediaSrc, "media-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ObjectSrc, "object-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ReportTo, "report-to") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ReportUri, "report-uri") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(Sandbox, "sandbox") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ScriptSrc, "script-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ScriptSrcElem, "script-src-elem") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ScriptSrcAttr, "script-src-attr") \
|
||||
__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") \
|
||||
#define ENUMERATE_DIRECTIVE_NAMES \
|
||||
__ENUMERATE_DIRECTIVE_NAME(BaseUri, "base-uri") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ChildSrc, "child-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ConnectSrc, "connect-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(DefaultSrc, "default-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FontSrc, "font-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FormAction, "form-action") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FrameAncestors, "frame-ancestors") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(FrameSrc, "frame-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ImgSrc, "img-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ManifestSrc, "manifest-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(MediaSrc, "media-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ObjectSrc, "object-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ReportTo, "report-to") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ReportUri, "report-uri") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(RequireTrustedTypesFor, "require-trusted-types-for") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(Sandbox, "sandbox") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ScriptSrc, "script-src") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ScriptSrcElem, "script-src-elem") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(ScriptSrcAttr, "script-src-attr") \
|
||||
__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")
|
||||
|
||||
#define __ENUMERATE_DIRECTIVE_NAME(name, value) extern FlyString name;
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace Web::TrustedTypes {
|
|||
__ENUMERATE_INJECTION_SINKS(Function, "Function") \
|
||||
__ENUMERATE_INJECTION_SINKS(HTMLIFrameElementsrcdoc, "HTMLIFrameElement srcdoc") \
|
||||
__ENUMERATE_INJECTION_SINKS(HTMLScriptElementsrc, "HTMLScriptElement src") \
|
||||
__ENUMERATE_INJECTION_SINKS(Locationhref, "Location href") \
|
||||
__ENUMERATE_INJECTION_SINKS(SVGScriptElementhref, "SVGScriptElement href") \
|
||||
ENUMERATE_GLOBAL_EVENT_HANDLERS(EVENT_HANDLERS_INJECTION_SINKS) \
|
||||
ENUMERATE_WINDOW_EVENT_HANDLERS(EVENT_HANDLERS_INJECTION_SINKS)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Miguel Sacristán Izcue <miguel_tete17@hotmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/TrustedTypes/RequireTrustedTypesForDirective.h>
|
||||
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Names.h>
|
||||
#include <LibWeb/DOMURL/DOMURL.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
|
||||
#include <LibWeb/TrustedTypes/TrustedScript.h>
|
||||
#include <LibWeb/TrustedTypes/TrustedTypePolicy.h>
|
||||
|
||||
namespace Web::TrustedTypes {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(RequireTrustedTypesForDirective);
|
||||
|
||||
RequireTrustedTypesForDirective::RequireTrustedTypesForDirective(String name, Vector<String> value)
|
||||
: Directive(move(name), move(value))
|
||||
{
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/trusted-types/#require-trusted-types-for-pre-navigation-check
|
||||
ContentSecurityPolicy::Directives::Directive::Result RequireTrustedTypesForDirective::pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request> request, NavigationType, GC::Ref<ContentSecurityPolicy::Policy const>) const
|
||||
{
|
||||
// 1. If request’s url’s scheme is not "javascript", return "Allowed" and abort further steps.
|
||||
if (request->url().scheme() != "javascript"sv)
|
||||
return Result::Allowed;
|
||||
|
||||
// 2. Let urlString be the result of running the URL serializer on request’s url.
|
||||
auto url_string = request->url().serialize();
|
||||
|
||||
// 3. Let encodedScriptSource be the result of removing the leading "javascript:" from urlString.
|
||||
auto const encoded_script_source = MUST(url_string.substring_from_byte_offset("javascript:"sv.length()));
|
||||
|
||||
// 4. Let convertedScriptSource be the result of executing Process value with a default policy algorithm, with the following arguments:
|
||||
// expectedType:
|
||||
// TrustedScript
|
||||
// global:
|
||||
// request’s clients’s global object:
|
||||
// input:
|
||||
// encodedScriptSource:
|
||||
// sink:
|
||||
// "Location href":
|
||||
auto converted_script_source = process_value_with_a_default_policy(
|
||||
TrustedTypeName::TrustedScript,
|
||||
request->client()->global_object(),
|
||||
Utf16String::from_utf8(encoded_script_source),
|
||||
InjectionSink::Locationhref);
|
||||
|
||||
// If that algorithm threw an error or convertedScriptSource is not a TrustedScript object, return "Blocked" and abort further steps.
|
||||
if (converted_script_source.is_error() || !converted_script_source.value().has_value())
|
||||
return Result::Blocked;
|
||||
|
||||
auto const* converted_script_source_value = converted_script_source.value().value().get_pointer<GC::Root<TrustedScript>>();
|
||||
|
||||
if (!converted_script_source_value)
|
||||
return Result::Blocked;
|
||||
|
||||
// 5. Set urlString to be the result of prepending "javascript:" to stringified convertedScriptSource.
|
||||
url_string = MUST(String::formatted("javascript:{}", (*converted_script_source_value)->to_string()));
|
||||
|
||||
// 6. Let newURL be the result of running the URL parser on urlString. If the parser returns a failure, return "Blocked" and abort further steps.
|
||||
auto const new_url = DOMURL::parse(url_string);
|
||||
if (!new_url.has_value())
|
||||
return Result::Blocked;
|
||||
|
||||
// 7. Set request’s url to newURL.
|
||||
request->set_url(new_url.value());
|
||||
|
||||
// 8. Return "Allowed".
|
||||
return Result::Allowed;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Miguel Sacristán Izcue <miguel_tete17@hotmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
|
||||
namespace Web::TrustedTypes {
|
||||
|
||||
// https://www.w3.org/TR/trusted-types/#require-trusted-types-for-csp-directive
|
||||
class RequireTrustedTypesForDirective final : public ContentSecurityPolicy::Directives::Directive {
|
||||
GC_CELL(RequireTrustedTypesForDirective, ContentSecurityPolicy::Directives::Directive)
|
||||
GC_DECLARE_ALLOCATOR(RequireTrustedTypesForDirective);
|
||||
|
||||
public:
|
||||
~RequireTrustedTypesForDirective() override = default;
|
||||
|
||||
Result pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request>, NavigationType, GC::Ref<ContentSecurityPolicy::Policy const>) const override;
|
||||
|
||||
private:
|
||||
RequireTrustedTypesForDirective(String name, Vector<String> value);
|
||||
};
|
||||
|
||||
}
|
|
@ -8,10 +8,13 @@
|
|||
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
|
||||
#include <LibWeb/TrustedTypes/TrustedHTML.h>
|
||||
#include <LibWeb/TrustedTypes/TrustedScript.h>
|
||||
#include <LibWeb/TrustedTypes/TrustedScriptURL.h>
|
||||
#include <LibWeb/TrustedTypes/TrustedTypePolicyFactory.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/CallbackType.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
|
@ -182,4 +185,72 @@ WebIDL::ExceptionOr<JS::Value> TrustedTypePolicy::get_trusted_type_policy_value(
|
|||
return policy_value;
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/trusted-types/#process-value-with-a-default-policy-algorithm
|
||||
WebIDL::ExceptionOr<Optional<TrustedType>> process_value_with_a_default_policy(TrustedTypeName trusted_type_name, JS::Object& global, Variant<GC::Root<TrustedHTML>, GC::Root<TrustedScript>, GC::Root<TrustedScriptURL>, Utf16String> input, InjectionSink sink)
|
||||
{
|
||||
auto& vm = global.vm();
|
||||
auto& realm = HTML::relevant_realm(global);
|
||||
|
||||
// 1. Let defaultPolicy be the value of global’s trusted type policy factory’s default policy.
|
||||
auto const& default_policy = as<HTML::WindowOrWorkerGlobalScopeMixin>(global).trusted_types()->default_policy();
|
||||
|
||||
// This algorithm routes a value to be assigned to an injection sink through a default policy, should one exist.
|
||||
// FIXME: Open an issue upstream. It is not immediately clear what to do if the default policy does not exist.
|
||||
// Ref: https://github.com/w3c/trusted-types/issues/595
|
||||
if (!default_policy)
|
||||
return Optional<TrustedType> {};
|
||||
|
||||
// 2. Let policyValue be the result of executing Get Trusted Type policy value, with the following arguments:
|
||||
// policy:
|
||||
// defaultPolicy
|
||||
// value:
|
||||
// stringified input
|
||||
// trustedTypeName:
|
||||
// expectedType’s type name
|
||||
// arguments:
|
||||
// « trustedTypeName, sink »
|
||||
// throwIfMissing:
|
||||
// false
|
||||
// 3. If the algorithm threw an error, rethrow the error and abort the following steps.
|
||||
auto arguments = GC::RootVector<JS::Value>(vm.heap());
|
||||
arguments.append(JS::PrimitiveString::create(vm, to_string(trusted_type_name)));
|
||||
arguments.append(JS::PrimitiveString::create(vm, to_string(sink)));
|
||||
auto policy_value = TRY(default_policy->get_trusted_type_policy_value(
|
||||
trusted_type_name,
|
||||
input.visit(
|
||||
[](auto& value) { return value->to_string(); },
|
||||
[](Utf16String& value) { return value; }),
|
||||
arguments,
|
||||
ThrowIfCallbackMissing::No));
|
||||
|
||||
// 4. If policyValue is null or undefined, return policyValue.
|
||||
if (policy_value.is_nullish())
|
||||
return Optional<TrustedType> {};
|
||||
|
||||
// 5. Let dataString be the result of stringifying policyValue.
|
||||
Utf16String data_string;
|
||||
switch (trusted_type_name) {
|
||||
case TrustedTypeName::TrustedHTML:
|
||||
case TrustedTypeName::TrustedScript:
|
||||
data_string = TRY(WebIDL::to_utf16_string(vm, policy_value));
|
||||
break;
|
||||
case TrustedTypeName::TrustedScriptURL:
|
||||
data_string = TRY(WebIDL::to_utf16_usv_string(vm, policy_value));
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// 6. Return a new instance of an interface with a type name trustedTypeName, with its associated data value set to dataString.
|
||||
switch (trusted_type_name) {
|
||||
case TrustedTypeName::TrustedHTML:
|
||||
return realm.create<TrustedHTML>(realm, move(data_string));
|
||||
case TrustedTypeName::TrustedScript:
|
||||
return realm.create<TrustedScript>(realm, move(data_string));
|
||||
case TrustedTypeName::TrustedScriptURL:
|
||||
return realm.create<TrustedScriptURL>(realm, move(data_string));
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,13 +9,17 @@
|
|||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/Bindings/TrustedTypePolicyPrototype.h>
|
||||
#include <LibWeb/TrustedTypes/InjectionSink.h>
|
||||
|
||||
namespace Web::TrustedTypes {
|
||||
|
||||
using TrustedTypesVariants = WebIDL::ExceptionOr<Variant<
|
||||
// https://www.w3.org/TR/trusted-types/#typedefdef-trustedtype
|
||||
using TrustedType = Variant<
|
||||
GC::Root<TrustedHTML>,
|
||||
GC::Root<TrustedScript>,
|
||||
GC::Root<TrustedScriptURL>>>;
|
||||
GC::Root<TrustedScriptURL>>;
|
||||
|
||||
using TrustedTypesVariants = WebIDL::ExceptionOr<TrustedType>;
|
||||
|
||||
enum class TrustedTypeName {
|
||||
TrustedHTML,
|
||||
|
@ -49,16 +53,18 @@ public:
|
|||
WebIDL::ExceptionOr<GC::Root<TrustedScript>> create_script(Utf16String const&, GC::RootVector<JS::Value> const&);
|
||||
WebIDL::ExceptionOr<GC::Root<TrustedScriptURL>> create_script_url(Utf16String const&, GC::RootVector<JS::Value> const&);
|
||||
|
||||
WebIDL::ExceptionOr<JS::Value> get_trusted_type_policy_value(TrustedTypeName, Utf16String const& value, GC::RootVector<JS::Value> const& values, ThrowIfCallbackMissing throw_if_missing);
|
||||
|
||||
private:
|
||||
explicit TrustedTypePolicy(JS::Realm&, Utf16String const&, TrustedTypePolicyOptions const&);
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
TrustedTypesVariants create_a_trusted_type(TrustedTypeName, Utf16String const&, GC::RootVector<JS::Value> const& values);
|
||||
|
||||
WebIDL::ExceptionOr<JS::Value> get_trusted_type_policy_value(TrustedTypeName, Utf16String const& value, GC::RootVector<JS::Value> const& values, ThrowIfCallbackMissing throw_if_missing);
|
||||
|
||||
Utf16String const m_name;
|
||||
TrustedTypePolicyOptions const m_options;
|
||||
};
|
||||
|
||||
WebIDL::ExceptionOr<Optional<TrustedType>> process_value_with_a_default_policy(TrustedTypeName, JS::Object&, Variant<GC::Root<TrustedHTML>, GC::Root<TrustedScript>, GC::Root<TrustedScriptURL>, Utf16String>, InjectionSink);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue