LibWeb: Implement createHTML for TrustedTypePolicy

This is the main mechanism by which users of the api can create
safe object with a callback for any needed sanitation of the values.
This commit is contained in:
Tete17 2025-07-31 14:40:11 +02:00 committed by Luke Wilde
commit c84c97b339
Notes: github-actions[bot] 2025-08-11 11:23:20 +00:00
3 changed files with 117 additions and 1 deletions

View file

@ -9,6 +9,9 @@
#include <LibGC/Ptr.h> #include <LibGC/Ptr.h>
#include <LibJS/Runtime/Realm.h> #include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/TrustedTypes/TrustedHTML.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/CallbackType.h>
#include <LibWeb/WebIDL/ExceptionOr.h> #include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::TrustedTypes { namespace Web::TrustedTypes {
@ -28,4 +31,98 @@ void TrustedTypePolicy::initialize(JS::Realm& realm)
Base::initialize(realm); Base::initialize(realm);
} }
// https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createhtml
WebIDL::ExceptionOr<GC::Root<TrustedHTML>> TrustedTypePolicy::create_html(String const& input, GC::RootVector<JS::Value> const& arguments)
{
// 1. Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
// policy
// this value
// trustedTypeName
// "TrustedHTML"
// value
// input
// arguments
// arguments
return create_a_trusted_type(TrustedTypeName::TrustedHTML, input, arguments);
}
// https://w3c.github.io/trusted-types/dist/spec/#create-a-trusted-type-algorithm
WebIDL::ExceptionOr<GC::Root<TrustedHTML>> TrustedTypePolicy::create_a_trusted_type(TrustedTypeName trusted_type_name, String const& value, GC::RootVector<JS::Value> const& arguments)
{
auto& vm = this->vm();
auto& realm = this->realm();
// 1. Let policyValue be the result of executing Get Trusted Type policy value with the same arguments
// as this algorithm and additionally true as throwIfMissing.
// 2. If the algorithm threw an error, rethrow the error and abort the following steps.
auto const policy_value = TRY(get_trusted_type_policy_value(trusted_type_name, value, arguments, ThrowIfCallbackMissing::Yes));
// 3. 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();
}
// 4. If policyValue is null or undefined, set dataString to the empty string.
if (policy_value.is_nullish())
data_string = ""_utf16;
// 5. Return a new instance of an interface with a type name trustedTypeName, with its associated data value set to dataString.
return realm.create<TrustedHTML>(realm, move(data_string));
}
// https://w3c.github.io/trusted-types/dist/spec/#abstract-opdef-get-trusted-type-policy-value
WebIDL::ExceptionOr<JS::Value> TrustedTypePolicy::get_trusted_type_policy_value(TrustedTypeName trusted_type_name, String const& value, GC::RootVector<JS::Value> const& values, ThrowIfCallbackMissing throw_if_missing)
{
auto& vm = this->vm();
// 1. Let functionName be a function name for the given trustedTypeName, based on the following table:
// 2. Let function be policys options[functionName].
GC::Ptr<WebIDL::CallbackType> function;
switch (trusted_type_name) {
case TrustedTypeName::TrustedHTML:
function = m_options.create_html;
break;
case TrustedTypeName::TrustedScript:
function = m_options.create_script;
break;
case TrustedTypeName::TrustedScriptURL:
function = m_options.create_script_url;
break;
default:
VERIFY_NOT_REACHED();
}
// 3. If function is null, then:
if (!function) {
// 1. If throwIfMissing throw a TypeError.
if (throw_if_missing == ThrowIfCallbackMissing::Yes)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Trying to create a trusted type without a callback"_string };
// 2. Else return null
return JS::js_null();
}
// 4. Let args be << value >>.
GC::RootVector<JS::Value> args(heap());
args.append(JS::PrimitiveString::create(vm, value));
// 5. Append each item in arguments to args.
args.extend(values);
// 6. Let policyValue be the result of invoking function with args and "rethrow".
auto const policy_value = TRY(WebIDL::invoke_callback(*function, {}, WebIDL::ExceptionBehavior::Rethrow, args));
// 7. Return policyValue.
return policy_value;
}
} }

View file

@ -12,6 +12,17 @@
namespace Web::TrustedTypes { namespace Web::TrustedTypes {
enum class TrustedTypeName {
TrustedHTML,
TrustedScript,
TrustedScriptURL,
};
enum class ThrowIfCallbackMissing {
Yes,
No
};
struct TrustedTypePolicyOptions { struct TrustedTypePolicyOptions {
GC::Root<WebIDL::CallbackType> create_html; GC::Root<WebIDL::CallbackType> create_html;
GC::Root<WebIDL::CallbackType> create_script; GC::Root<WebIDL::CallbackType> create_script;
@ -27,10 +38,16 @@ public:
String const& name() const { return m_name; } String const& name() const { return m_name; }
WebIDL::ExceptionOr<GC::Root<TrustedHTML>> create_html(String const&, GC::RootVector<JS::Value> const&);
private: private:
explicit TrustedTypePolicy(JS::Realm&, String const&, TrustedTypePolicyOptions const&); explicit TrustedTypePolicy(JS::Realm&, String const&, TrustedTypePolicyOptions const&);
virtual void initialize(JS::Realm&) override; virtual void initialize(JS::Realm&) override;
WebIDL::ExceptionOr<GC::Root<TrustedHTML>> create_a_trusted_type(TrustedTypeName, String const&, GC::RootVector<JS::Value> const& values);
WebIDL::ExceptionOr<JS::Value> get_trusted_type_policy_value(TrustedTypeName, String const& value, GC::RootVector<JS::Value> const& values, ThrowIfCallbackMissing throw_if_missing);
String const m_name; String const m_name;
TrustedTypePolicyOptions const m_options; TrustedTypePolicyOptions const m_options;
}; };

View file

@ -1,8 +1,10 @@
#import <TrustedTypes/TrustedHTML.idl>
// https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy // https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy
[Exposed=(Window,Worker)] [Exposed=(Window,Worker)]
interface TrustedTypePolicy { interface TrustedTypePolicy {
readonly attribute DOMString name; readonly attribute DOMString name;
[FIXME] TrustedHTML createHTML(DOMString input, any... arguments); TrustedHTML createHTML(DOMString input, any... arguments);
[FIXME] TrustedScript createScript(DOMString input, any... arguments); [FIXME] TrustedScript createScript(DOMString input, any... arguments);
[FIXME] TrustedScriptURL createScriptURL(DOMString input, any... arguments); [FIXME] TrustedScriptURL createScriptURL(DOMString input, any... arguments);
}; };