mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWeb: Introduce Content Security Policy policies and directives
These form the basis of Content Security Policy. A policy is a collection of directives that are parsed from either the Content-Security-Policy(-Report-Only) HTTP header, or the `<meta>` element. The directives are what restrict the operations can be performed in the current global execution context. For example, "frame-ancestors: none" tells us to prevent the page from being loaded in an embedded context, such as `<iframe>`. You can see it a bit like OpenBSD's pledge() functionality, but for the web platform: https://man.openbsd.org/pledge.2
This commit is contained in:
parent
d17bd2c5f1
commit
e34a6c86b9
Notes:
github-actions[bot]
2025-03-04 13:28:21 +00:00
Author: https://github.com/Lubrsi
Commit: e34a6c86b9
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3662
20 changed files with 846 additions and 3 deletions
|
@ -36,6 +36,13 @@ set(SOURCES
|
|||
Clipboard/ClipboardItem.cpp
|
||||
Compression/CompressionStream.cpp
|
||||
Compression/DecompressionStream.cpp
|
||||
ContentSecurityPolicy/Directives/Directive.cpp
|
||||
ContentSecurityPolicy/Directives/DirectiveFactory.cpp
|
||||
ContentSecurityPolicy/Directives/Names.cpp
|
||||
ContentSecurityPolicy/Directives/SerializedDirective.cpp
|
||||
ContentSecurityPolicy/Policy.cpp
|
||||
ContentSecurityPolicy/PolicyList.cpp
|
||||
ContentSecurityPolicy/SerializedPolicy.cpp
|
||||
CredentialManagement/Credential.cpp
|
||||
CredentialManagement/CredentialsContainer.cpp
|
||||
CredentialManagement/FederatedCredential.cpp
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/SerializedDirective.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(Directive);
|
||||
|
||||
Directive::Directive(String name, Vector<String> value)
|
||||
: m_name(move(name))
|
||||
, m_value(move(value))
|
||||
{
|
||||
}
|
||||
|
||||
GC::Ref<Directive> Directive::clone(JS::Realm& realm) const
|
||||
{
|
||||
return create_directive(realm, m_name, m_value);
|
||||
}
|
||||
|
||||
SerializedDirective Directive::serialize() const
|
||||
{
|
||||
return SerializedDirective {
|
||||
.name = m_name,
|
||||
.value = m_value,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
112
Libraries/LibWeb/ContentSecurityPolicy/Directives/Directive.h
Normal file
112
Libraries/LibWeb/ContentSecurityPolicy/Directives/Directive.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibGC/CellAllocator.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directives
|
||||
// Each policy contains an ordered set of directives (its directive set), each of which controls a specific behavior.
|
||||
// The directives defined in this document are described in detail in § 6 Content Security Policy Directives.
|
||||
class Directive : public JS::Cell {
|
||||
GC_CELL(Directive, JS::Cell)
|
||||
GC_DECLARE_ALLOCATOR(Directive);
|
||||
|
||||
public:
|
||||
enum class Result {
|
||||
Blocked,
|
||||
Allowed,
|
||||
};
|
||||
|
||||
enum class NavigationType {
|
||||
FormSubmission,
|
||||
Other,
|
||||
};
|
||||
|
||||
enum class CheckType {
|
||||
Source,
|
||||
Response,
|
||||
};
|
||||
|
||||
enum class InlineType {
|
||||
Navigation,
|
||||
Script,
|
||||
ScriptAttribute,
|
||||
Style,
|
||||
StyleAttribute,
|
||||
};
|
||||
|
||||
virtual ~Directive() = default;
|
||||
|
||||
// Directives have a number of associated algorithms:
|
||||
// https://w3c.github.io/webappsec-csp/#directive-pre-request-check
|
||||
// 1. A pre-request check, which takes a request and a policy as an argument, and is executed during
|
||||
// § 4.1.2 Should request be blocked by Content Security Policy?. This algorithm returns "Allowed"
|
||||
// unless otherwise specified.
|
||||
[[nodiscard]] virtual Result pre_request_check(JS::Realm&, GC::Ref<Fetch::Infrastructure::Request const>, GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directive-post-request-check
|
||||
// 2. A post-request check, which takes a request, a response, and a policy as arguments, and is executed during
|
||||
// § 4.1.3 Should response to request be blocked by Content Security Policy?. This algorithm returns "Allowed"
|
||||
// unless otherwise specified.
|
||||
[[nodiscard]] virtual Result post_request_check(JS::Realm&, GC::Ref<Fetch::Infrastructure::Request const>, GC::Ref<Fetch::Infrastructure::Response const>, GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directive-inline-check
|
||||
// 3. An inline check, which takes an Element, a type string, a policy, and a source string as arguments, and is
|
||||
// executed during § 4.2.3 Should element’s inline type behavior be blocked by Content Security Policy? and
|
||||
// during § 4.2.4 Should navigation request of type be blocked by Content Security Policy? for javascript:
|
||||
// requests. This algorithm returns "Allowed" unless otherwise specified.
|
||||
[[nodiscard]] virtual Result inline_check(JS::Realm&, GC::Ptr<DOM::Element const>, InlineType, GC::Ref<Policy const>, String const&) const { return Result::Allowed; }
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directive-initialization
|
||||
// 4. An initialization, which takes a Document or global object and a policy as arguments. This algorithm is
|
||||
// executed during § 4.2.1 Run CSP initialization for a Document and § 4.2.6 Run CSP initialization for
|
||||
// a global object. Unless otherwise specified, it has no effect and it returns "Allowed".
|
||||
[[nodiscard]] virtual Result initialization(Variant<GC::Ref<DOM::Document const>, GC::Ref<HTML::WorkerGlobalScope const>>, GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directive-pre-navigation-check
|
||||
// 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.
|
||||
[[nodiscard]] virtual Result pre_navigation_check(GC::Ref<Fetch::Infrastructure::Request const>, 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"),
|
||||
// a response, a navigable, a check type string ("source" or "response"), and a policy as arguments, and is
|
||||
// executed during § 4.2.5 Should navigation response to navigation request of type in target be blocked by
|
||||
// Content Security Policy?. It returns "Allowed" unless otherwise specified.
|
||||
[[nodiscard]] virtual Result navigation_response_check(GC::Ref<Fetch::Infrastructure::Request const>, NavigationType, GC::Ref<Fetch::Infrastructure::Response const>, GC::Ref<HTML::Navigable const>, CheckType, GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#directive-webrtc-pre-connect-check
|
||||
// 7. A webrtc pre-connect check, which takes a policy, and is executed during § 4.3.1 Should RTC connections be
|
||||
// blocked for global?. It returns "Allowed" unless otherwise specified.
|
||||
[[nodiscard]] virtual Result webrtc_pre_connect_check(GC::Ref<Policy const>) const { return Result::Allowed; }
|
||||
|
||||
[[nodiscard]] String const& name() const { return m_name; }
|
||||
[[nodiscard]] Vector<String> const& value() const { return m_value; }
|
||||
|
||||
[[nodiscard]] GC::Ref<Directive> clone(JS::Realm&) const;
|
||||
[[nodiscard]] SerializedDirective serialize() const;
|
||||
|
||||
protected:
|
||||
Directive(String name, Vector<String> value);
|
||||
|
||||
private:
|
||||
// https://w3c.github.io/webappsec-csp/#directive-name
|
||||
// https://w3c.github.io/webappsec-csp/#directive-value
|
||||
// Each directive is a name / value pair. The name is a non-empty string, and the value is a set of non-empty strings.
|
||||
// The value MAY be empty.
|
||||
String m_name;
|
||||
Vector<String> m_value;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
||||
GC::Ref<Directive> create_directive(JS::Realm& realm, String name, Vector<String> value)
|
||||
{
|
||||
dbgln("Potential FIXME: Creating unknown Content Security Policy directive: {}", name);
|
||||
return realm.create<Directive>(move(name), move(value));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
||||
[[nodiscard]] GC::Ref<Directive> create_directive(JS::Realm&, String name, Vector<String> value);
|
||||
|
||||
}
|
16
Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.cpp
Normal file
16
Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Names.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives::Names {
|
||||
|
||||
#define __ENUMERATE_DIRECTIVE_NAME(name, value) \
|
||||
FlyString name = value##_fly_string;
|
||||
ENUMERATE_DIRECTIVE_NAMES
|
||||
#undef __ENUMERATE_DIRECTIVE_NAME
|
||||
|
||||
}
|
44
Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.h
Normal file
44
Libraries/LibWeb/ContentSecurityPolicy/Directives/Names.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
|
||||
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(WebRTC, "webrtc") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(WorkerSrc, "worker-src")
|
||||
|
||||
#define __ENUMERATE_DIRECTIVE_NAME(name, value) extern FlyString name;
|
||||
ENUMERATE_DIRECTIVE_NAMES
|
||||
#undef __ENUMERATE_DIRECTIVE_NAME
|
||||
|
||||
void initialize_strings();
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/SerializedDirective.h>
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Web::ContentSecurityPolicy::Directives::SerializedDirective const& serialized_directive)
|
||||
{
|
||||
TRY(encoder.encode(serialized_directive.name));
|
||||
TRY(encoder.encode(serialized_directive.value));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Web::ContentSecurityPolicy::Directives::SerializedDirective> decode(Decoder& decoder)
|
||||
{
|
||||
Web::ContentSecurityPolicy::Directives::SerializedDirective serialized_directive {};
|
||||
|
||||
serialized_directive.name = TRY(decoder.decode<String>());
|
||||
serialized_directive.value = TRY(decoder.decode<Vector<String>>());
|
||||
|
||||
return serialized_directive;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
|
||||
struct SerializedDirective {
|
||||
String name;
|
||||
Vector<String> value;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Web::ContentSecurityPolicy::Directives::SerializedDirective const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Web::ContentSecurityPolicy::Directives::SerializedDirective> decode(Decoder&);
|
||||
|
||||
}
|
199
Libraries/LibWeb/ContentSecurityPolicy/Policy.cpp
Normal file
199
Libraries/LibWeb/ContentSecurityPolicy/Policy.cpp
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/GenericLexer.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/DirectiveFactory.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/SerializedDirective.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/SerializedPolicy.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
|
||||
#include <LibWeb/Infra/CharacterTypes.h>
|
||||
#include <LibWeb/Infra/Strings.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(Policy);
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#abstract-opdef-parse-a-serialized-csp
|
||||
GC::Ref<Policy> Policy::parse_a_serialized_csp(JS::Realm& realm, Variant<ByteBuffer, String> serialized, Source source, Disposition disposition)
|
||||
{
|
||||
// To parse a serialized CSP, given a byte sequence or string serialized, a source source, and a disposition disposition,
|
||||
// execute the following steps.
|
||||
// This algorithm returns a Content Security Policy object. If serialized could not be parsed, the object’s directive
|
||||
// set will be empty.
|
||||
|
||||
// 1. If serialized is a byte sequence, then set serialized to be the result of isomorphic decoding serialized.
|
||||
auto serialized_string = serialized.has<String>()
|
||||
? serialized.get<String>()
|
||||
: Infra::isomorphic_decode(serialized.get<ByteBuffer>());
|
||||
|
||||
// 2. Let policy be a new policy with an empty directive set, a source of source, and a disposition of disposition.
|
||||
auto policy = realm.create<Policy>();
|
||||
policy->m_source = source;
|
||||
policy->m_disposition = disposition;
|
||||
|
||||
// 3. For each token returned by strictly splitting serialized on the U+003B SEMICOLON character (;):
|
||||
auto tokens = MUST(serialized_string.split(';', SplitBehavior::KeepEmpty));
|
||||
for (auto token : tokens) {
|
||||
// 1. Strip leading and trailing ASCII whitespace from token.
|
||||
auto stripped_token = MUST(token.trim(Infra::ASCII_WHITESPACE));
|
||||
auto stripped_token_view = stripped_token.bytes_as_string_view();
|
||||
|
||||
// 2. If token is an empty string, or if token is not an ASCII string, continue.
|
||||
if (stripped_token.is_empty() || !all_of(stripped_token_view, is_ascii))
|
||||
continue;
|
||||
|
||||
// 3. Let directive name be the result of collecting a sequence of code points from token which are not
|
||||
// ASCII whitespace.
|
||||
GenericLexer lexer(stripped_token_view);
|
||||
auto directive_name = lexer.consume_until(Infra::is_ascii_whitespace);
|
||||
|
||||
// 4. Set directive name to be the result of running ASCII lowercase on directive name.
|
||||
// Spec Note: Directive names are case-insensitive, that is: script-SRC 'none' and ScRiPt-sRc 'none' are
|
||||
// equivalent.
|
||||
auto lowercase_directive_name = MUST(Infra::to_ascii_lowercase(directive_name));
|
||||
|
||||
// 5. If policy’s directive set contains a directive whose name is directive name, continue.
|
||||
if (policy->contains_directive_with_name(lowercase_directive_name)) {
|
||||
// Spec Note: In this case, the user agent SHOULD notify developers that a duplicate directive was
|
||||
// ignored. A console warning might be appropriate, for example.
|
||||
dbgln("Ignoring duplicate Content Security Policy directive: {}", lowercase_directive_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 6. Let directive value be the result of splitting token on ASCII whitespace.
|
||||
auto rest_of_the_token = lexer.consume_all();
|
||||
auto directive_value_views = rest_of_the_token.split_view_if(Infra::is_ascii_whitespace);
|
||||
|
||||
Vector<String> directive_value;
|
||||
for (auto directive_value_view : directive_value_views) {
|
||||
String directive_value_entry = MUST(String::from_utf8(directive_value_view));
|
||||
directive_value.append(move(directive_value_entry));
|
||||
}
|
||||
|
||||
// 7. Let directive be a new directive whose name is directive name, and value is directive value.
|
||||
auto directive = Directives::create_directive(realm, move(lowercase_directive_name), move(directive_value));
|
||||
|
||||
// 8. Append directive to policy’s directive set.
|
||||
policy->m_directives.append(directive);
|
||||
}
|
||||
|
||||
// 4. Return policy.
|
||||
return policy;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#abstract-opdef-parse-a-responses-content-security-policies
|
||||
GC::Ref<PolicyList> Policy::parse_a_responses_content_security_policies(JS::Realm& realm, GC::Ref<Fetch::Infrastructure::Response const> response)
|
||||
{
|
||||
// To parse a response’s Content Security Policies given a response response, execute the following steps.
|
||||
// This algorithm returns a list of Content Security Policy objects. If the policies cannot be parsed,
|
||||
// the returned list will be empty.
|
||||
|
||||
// 1. Let policies be an empty list.
|
||||
GC::RootVector<GC::Ref<Policy>> policies(realm.heap());
|
||||
|
||||
// 2. For each token returned by extracting header list values given Content-Security-Policy and response’s header
|
||||
// list:
|
||||
auto enforce_policy_tokens_or_failure = Fetch::Infrastructure::extract_header_list_values("Content-Security-Policy"sv.bytes(), response->header_list());
|
||||
auto enforce_policy_tokens = enforce_policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? enforce_policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
|
||||
for (auto enforce_policy_token : enforce_policy_tokens) {
|
||||
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "enforce".
|
||||
auto policy = parse_a_serialized_csp(realm, enforce_policy_token, Policy::Source::Header, Policy::Disposition::Enforce);
|
||||
|
||||
// 2. If policy’s directive set is not empty, append policy to policies.
|
||||
if (!policy->m_directives.is_empty()) {
|
||||
policies.append(policy);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. For each token returned by extracting header list values given Content-Security-Policy-Report-Only and
|
||||
// response’s header list:
|
||||
auto report_policy_tokens_or_failure = Fetch::Infrastructure::extract_header_list_values("Content-Security-Policy-Report-Only"sv.bytes(), response->header_list());
|
||||
auto report_policy_tokens = report_policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? report_policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
|
||||
for (auto report_policy_token : report_policy_tokens) {
|
||||
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "report".
|
||||
auto policy = parse_a_serialized_csp(realm, report_policy_token, Policy::Source::Header, Policy::Disposition::Report);
|
||||
|
||||
// 2. If policy’s directive set is not empty, append policy to policies.
|
||||
if (!policy->m_directives.is_empty()) {
|
||||
policies.append(policy);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. For each policy of policies:
|
||||
for (auto& policy : policies) {
|
||||
// 1. Set policy’s self-origin to response’s url's origin.
|
||||
policy->m_self_origin = response->url()->origin();
|
||||
}
|
||||
|
||||
// 5. Return policies.
|
||||
return PolicyList::create(realm, policies);
|
||||
}
|
||||
|
||||
GC::Ref<Policy> Policy::create_from_serialized_policy(JS::Realm& realm, SerializedPolicy const& serialized_policy)
|
||||
{
|
||||
auto policy = realm.create<Policy>();
|
||||
|
||||
for (auto const& serialized_directive : serialized_policy.directives) {
|
||||
auto directive = Directives::create_directive(realm, serialized_directive.name, serialized_directive.value);
|
||||
policy->m_directives.append(directive);
|
||||
}
|
||||
|
||||
policy->m_disposition = serialized_policy.disposition;
|
||||
policy->m_source = serialized_policy.source;
|
||||
policy->m_self_origin = serialized_policy.self_origin;
|
||||
return policy;
|
||||
}
|
||||
|
||||
bool Policy::contains_directive_with_name(StringView name) const
|
||||
{
|
||||
auto maybe_directive = m_directives.find_if([name](auto const& directive) {
|
||||
return directive->name() == name;
|
||||
});
|
||||
return !maybe_directive.is_end();
|
||||
}
|
||||
|
||||
GC::Ref<Policy> Policy::clone(JS::Realm& realm) const
|
||||
{
|
||||
auto policy = realm.create<Policy>();
|
||||
|
||||
for (auto directive : m_directives) {
|
||||
auto cloned_directive = directive->clone(realm);
|
||||
policy->m_directives.append(cloned_directive);
|
||||
}
|
||||
|
||||
policy->m_disposition = m_disposition;
|
||||
policy->m_source = m_source;
|
||||
policy->m_self_origin = m_self_origin;
|
||||
return policy;
|
||||
}
|
||||
|
||||
SerializedPolicy Policy::serialize() const
|
||||
{
|
||||
Vector<Directives::SerializedDirective> serialized_directives;
|
||||
|
||||
for (auto directive : m_directives) {
|
||||
serialized_directives.append(directive->serialize());
|
||||
}
|
||||
|
||||
return SerializedPolicy {
|
||||
.directives = move(serialized_directives),
|
||||
.disposition = m_disposition,
|
||||
.source = m_source,
|
||||
.self_origin = m_self_origin,
|
||||
};
|
||||
}
|
||||
|
||||
void Policy::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_directives);
|
||||
}
|
||||
|
||||
}
|
82
Libraries/LibWeb/ContentSecurityPolicy/Policy.h
Normal file
82
Libraries/LibWeb/ContentSecurityPolicy/Policy.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibURL/Origin.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/Directive.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
|
||||
#define ENUMERATE_DISPOSITION_TYPES \
|
||||
__ENUMERATE_DISPOSITION_TYPE(Enforce, "enforce") \
|
||||
__ENUMERATE_DISPOSITION_TYPE(Report, "report")
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#content-security-policy-object
|
||||
// A policy defines allowed and restricted behaviors, and may be applied to a Document, WorkerGlobalScope,
|
||||
// or WorkletGlobalScope.
|
||||
class Policy final : public JS::Cell {
|
||||
GC_CELL(Policy, JS::Cell);
|
||||
GC_DECLARE_ALLOCATOR(Policy);
|
||||
|
||||
public:
|
||||
enum class Disposition {
|
||||
#define __ENUMERATE_DISPOSITION_TYPE(type, _) type,
|
||||
ENUMERATE_DISPOSITION_TYPES
|
||||
#undef __ENUMERATE_DISPOSITION_TYPE
|
||||
};
|
||||
|
||||
enum class Source {
|
||||
Header,
|
||||
Meta,
|
||||
};
|
||||
|
||||
~Policy() = default;
|
||||
|
||||
[[nodiscard]] static GC::Ref<Policy> parse_a_serialized_csp(JS::Realm&, Variant<ByteBuffer, String> serialized, Source source, Disposition disposition);
|
||||
[[nodiscard]] static GC::Ref<PolicyList> parse_a_responses_content_security_policies(JS::Realm&, GC::Ref<Fetch::Infrastructure::Response const> response);
|
||||
[[nodiscard]] static GC::Ref<Policy> create_from_serialized_policy(JS::Realm&, SerializedPolicy const&);
|
||||
|
||||
[[nodiscard]] Vector<GC::Ref<Directives::Directive>> const& directives() const { return m_directives; }
|
||||
[[nodiscard]] Disposition disposition() const { return m_disposition; }
|
||||
[[nodiscard]] Source source() const { return m_source; }
|
||||
[[nodiscard]] URL::Origin const& self_origin() const { return m_self_origin; }
|
||||
|
||||
[[nodiscard]] bool contains_directive_with_name(StringView name) const;
|
||||
|
||||
[[nodiscard]] GC::Ref<Policy> clone(JS::Realm&) const;
|
||||
[[nodiscard]] SerializedPolicy serialize() const;
|
||||
|
||||
protected:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
Policy() = default;
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#policy-directive-set
|
||||
// Each policy has an associated directive set, which is an ordered set of directives that define the policy’s
|
||||
// implications when applied.
|
||||
Vector<GC::Ref<Directives::Directive>> m_directives;
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#policy-disposition
|
||||
// Each policy has an associated disposition, which is either "enforce" or "report".
|
||||
Disposition m_disposition { Disposition::Enforce };
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#policy-source
|
||||
// Each policy has an associated source, which is either "header" or "meta".
|
||||
Source m_source { Source::Header };
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#policy-self-origin
|
||||
// Each policy has an associated self-origin, which is an origin that is used when matching the 'self' keyword.
|
||||
// Spec Note: This is needed to facilitate the 'self' checks of local scheme documents/workers that have inherited
|
||||
// their policy but have an opaque origin. Most of the time this will simply be the environment settings
|
||||
// object’s origin.
|
||||
URL::Origin m_self_origin;
|
||||
};
|
||||
|
||||
}
|
104
Libraries/LibWeb/ContentSecurityPolicy/PolicyList.cpp
Normal file
104
Libraries/LibWeb/ContentSecurityPolicy/PolicyList.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGC/RootVector.h>
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/SerializedPolicy.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(PolicyList);
|
||||
|
||||
GC::Ref<PolicyList> PolicyList::create(JS::Realm& realm, GC::RootVector<GC::Ref<Policy>> const& policies)
|
||||
{
|
||||
auto policy_list = realm.create<PolicyList>();
|
||||
for (auto policy : policies)
|
||||
policy_list->m_policies.append(policy);
|
||||
return policy_list;
|
||||
}
|
||||
|
||||
GC::Ref<PolicyList> PolicyList::create(JS::Realm& realm, Vector<SerializedPolicy> const& serialized_policies)
|
||||
{
|
||||
auto policy_list = realm.create<PolicyList>();
|
||||
for (auto const& serialized_policy : serialized_policies) {
|
||||
auto policy = Policy::create_from_serialized_policy(realm, serialized_policy);
|
||||
policy_list->m_policies.append(policy);
|
||||
}
|
||||
return policy_list;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#get-csp-of-object
|
||||
GC::Ptr<PolicyList> PolicyList::from_object(JS::Object& object)
|
||||
{
|
||||
// 1. If object is a Document return object’s policy container's CSP list.
|
||||
if (is<DOM::Document>(object)) {
|
||||
auto& document = static_cast<DOM::Document&>(object);
|
||||
return document.policy_container()->csp_list;
|
||||
}
|
||||
|
||||
// 2. If object is a Window or a WorkerGlobalScope or a WorkletGlobalScope, return environment settings object’s
|
||||
// policy container's CSP list.
|
||||
// FIXME: File a spec issue to make this look at ShadowRealmGlobalScope to support ShadowRealm.
|
||||
if (is<HTML::Window>(object) || is<HTML::WorkerGlobalScope>(object) || is<HTML::ShadowRealmGlobalScope>(object)) {
|
||||
auto& settings = HTML::relevant_principal_settings_object(object);
|
||||
return settings.policy_container()->csp_list;
|
||||
}
|
||||
|
||||
// 3. Return null.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PolicyList::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_policies);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#contains-a-header-delivered-content-security-policy
|
||||
bool PolicyList::contains_header_delivered_policy() const
|
||||
{
|
||||
// A CSP list contains a header-delivered Content Security Policy if it contains a policy whose source is "header".
|
||||
auto header_delivered_entry = m_policies.find_if([](auto const& policy) {
|
||||
return policy->source() == Policy::Source::Header;
|
||||
});
|
||||
|
||||
return !header_delivered_entry.is_end();
|
||||
}
|
||||
|
||||
HTML::SandboxingFlagSet PolicyList::csp_derived_sandboxing_flags() const
|
||||
{
|
||||
dbgln("FIXME: Implement PolicyList::csp_derived_sandboxing_flags");
|
||||
return HTML::SandboxingFlagSet {};
|
||||
}
|
||||
|
||||
GC::Ref<PolicyList> PolicyList::clone(JS::Realm& realm) const
|
||||
{
|
||||
auto policy_list = realm.create<PolicyList>();
|
||||
for (auto policy : m_policies) {
|
||||
auto cloned_policy = policy->clone(realm);
|
||||
policy_list->m_policies.append(cloned_policy);
|
||||
}
|
||||
return policy_list;
|
||||
}
|
||||
|
||||
Vector<SerializedPolicy> PolicyList::serialize() const
|
||||
{
|
||||
Vector<SerializedPolicy> serialized_policies;
|
||||
|
||||
for (auto policy : m_policies) {
|
||||
serialized_policies.append(policy->serialize());
|
||||
}
|
||||
|
||||
return serialized_policies;
|
||||
}
|
||||
|
||||
}
|
44
Libraries/LibWeb/ContentSecurityPolicy/PolicyList.h
Normal file
44
Libraries/LibWeb/ContentSecurityPolicy/PolicyList.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGC/CellAllocator.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
|
||||
class PolicyList final : public JS::Cell {
|
||||
GC_CELL(PolicyList, JS::Cell);
|
||||
GC_DECLARE_ALLOCATOR(PolicyList);
|
||||
|
||||
public:
|
||||
[[nodiscard]] static GC::Ref<PolicyList> create(JS::Realm&, GC::RootVector<GC::Ref<Policy>> const&);
|
||||
[[nodiscard]] static GC::Ref<PolicyList> create(JS::Realm&, Vector<SerializedPolicy> const&);
|
||||
[[nodiscard]] static GC::Ptr<PolicyList> from_object(JS::Object&);
|
||||
|
||||
virtual ~PolicyList() = default;
|
||||
|
||||
[[nodiscard]] Vector<GC::Ref<Policy>> const& policies() const { return m_policies; }
|
||||
|
||||
[[nodiscard]] bool contains_header_delivered_policy() const;
|
||||
|
||||
[[nodiscard]] HTML::SandboxingFlagSet csp_derived_sandboxing_flags() const;
|
||||
|
||||
[[nodiscard]] GC::Ref<PolicyList> clone(JS::Realm&) const;
|
||||
[[nodiscard]] Vector<SerializedPolicy> serialize() const;
|
||||
|
||||
protected:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
PolicyList() = default;
|
||||
|
||||
Vector<GC::Ref<Policy>> m_policies;
|
||||
};
|
||||
|
||||
}
|
37
Libraries/LibWeb/ContentSecurityPolicy/SerializedPolicy.cpp
Normal file
37
Libraries/LibWeb/ContentSecurityPolicy/SerializedPolicy.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/SerializedPolicy.h>
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Web::ContentSecurityPolicy::SerializedPolicy const& serialized_policy)
|
||||
{
|
||||
TRY(encoder.encode(serialized_policy.directives));
|
||||
TRY(encoder.encode(serialized_policy.disposition));
|
||||
TRY(encoder.encode(serialized_policy.source));
|
||||
TRY(encoder.encode(serialized_policy.self_origin));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
ErrorOr<Web::ContentSecurityPolicy::SerializedPolicy> decode(Decoder& decoder)
|
||||
{
|
||||
Web::ContentSecurityPolicy::SerializedPolicy serialized_policy {};
|
||||
|
||||
serialized_policy.directives = TRY(decoder.decode<Vector<Web::ContentSecurityPolicy::Directives::SerializedDirective>>());
|
||||
serialized_policy.disposition = TRY(decoder.decode<Web::ContentSecurityPolicy::Policy::Disposition>());
|
||||
serialized_policy.source = TRY(decoder.decode<Web::ContentSecurityPolicy::Policy::Source>());
|
||||
serialized_policy.self_origin = TRY(decoder.decode<URL::Origin>());
|
||||
|
||||
return serialized_policy;
|
||||
}
|
||||
|
||||
}
|
32
Libraries/LibWeb/ContentSecurityPolicy/SerializedPolicy.h
Normal file
32
Libraries/LibWeb/ContentSecurityPolicy/SerializedPolicy.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibIPC/Forward.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/SerializedDirective.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
|
||||
struct SerializedPolicy {
|
||||
Vector<Directives::SerializedDirective> directives;
|
||||
Policy::Disposition disposition;
|
||||
Policy::Source source;
|
||||
URL::Origin self_origin;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
ErrorOr<void> encode(Encoder&, Web::ContentSecurityPolicy::SerializedPolicy const&);
|
||||
|
||||
template<>
|
||||
ErrorOr<Web::ContentSecurityPolicy::SerializedPolicy> decode(Decoder&);
|
||||
|
||||
}
|
|
@ -98,6 +98,17 @@ class CompressionStream;
|
|||
class DecompressionStream;
|
||||
}
|
||||
|
||||
namespace Web::ContentSecurityPolicy {
|
||||
class Policy;
|
||||
class PolicyList;
|
||||
struct SerializedPolicy;
|
||||
}
|
||||
|
||||
namespace Web::ContentSecurityPolicy::Directives {
|
||||
class Directive;
|
||||
struct SerializedDirective;
|
||||
}
|
||||
|
||||
namespace Web::Cookie {
|
||||
struct Cookie;
|
||||
struct ParsedCookie;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Policy.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/PolicyList.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/URL.h>
|
||||
#include <LibWeb/HTML/PolicyContainers.h>
|
||||
#include <LibWeb/HTML/SerializedPolicyContainer.h>
|
||||
|
@ -15,7 +17,8 @@ namespace Web::HTML {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(PolicyContainer);
|
||||
|
||||
PolicyContainer::PolicyContainer(JS::Realm&)
|
||||
PolicyContainer::PolicyContainer(JS::Realm& realm)
|
||||
: csp_list(realm.create<ContentSecurityPolicy::PolicyList>())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,6 +37,7 @@ bool url_requires_storing_the_policy_container_in_history(URL::URL const& url)
|
|||
GC::Ref<PolicyContainer> create_a_policy_container_from_serialized_policy_container(JS::Realm& realm, SerializedPolicyContainer const& serialized_policy_container)
|
||||
{
|
||||
GC::Ref<PolicyContainer> result = realm.create<PolicyContainer>(realm);
|
||||
result->csp_list = ContentSecurityPolicy::PolicyList::create(realm, serialized_policy_container.csp_list);
|
||||
result->embedder_policy = serialized_policy_container.embedder_policy;
|
||||
result->referrer_policy = serialized_policy_container.referrer_policy;
|
||||
return result;
|
||||
|
@ -45,7 +49,8 @@ GC::Ref<PolicyContainer> PolicyContainer::clone(JS::Realm& realm) const
|
|||
// 1. Let clone be a new policy container.
|
||||
auto clone = realm.create<PolicyContainer>(realm);
|
||||
|
||||
// FIXME: 2. For each policy in policyContainer's CSP list, append a copy of policy into clone's CSP list.
|
||||
// 2. For each policy in policyContainer's CSP list, append a copy of policy into clone's CSP list.
|
||||
clone->csp_list = csp_list->clone(realm);
|
||||
|
||||
// 3. Set clone's embedder policy to a copy of policyContainer's embedder policy.
|
||||
// NOTE: This is a C++ copy.
|
||||
|
@ -61,9 +66,16 @@ GC::Ref<PolicyContainer> PolicyContainer::clone(JS::Realm& realm) const
|
|||
SerializedPolicyContainer PolicyContainer::serialize() const
|
||||
{
|
||||
return SerializedPolicyContainer {
|
||||
.csp_list = csp_list->serialize(),
|
||||
.embedder_policy = embedder_policy,
|
||||
.referrer_policy = referrer_policy,
|
||||
};
|
||||
}
|
||||
|
||||
void PolicyContainer::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(csp_list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ public:
|
|||
virtual ~PolicyContainer() = default;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/origin.html#policy-container-csp-list
|
||||
// FIXME: A CSP list, which is a CSP list. It is initially empty.
|
||||
// A CSP list, which is a CSP list. It is initially empty.
|
||||
GC::Ref<ContentSecurityPolicy::PolicyList> csp_list;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/origin.html#policy-container-embedder-policy
|
||||
// An embedder policy, which is an embedder policy. It is initially a new embedder policy.
|
||||
|
@ -39,6 +40,9 @@ public:
|
|||
[[nodiscard]] GC::Ref<PolicyContainer> clone(JS::Realm&) const;
|
||||
[[nodiscard]] SerializedPolicyContainer serialize() const;
|
||||
|
||||
protected:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
PolicyContainer(JS::Realm&);
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace IPC {
|
|||
template<>
|
||||
ErrorOr<void> encode(Encoder& encoder, Web::HTML::SerializedPolicyContainer const& serialized_policy_container)
|
||||
{
|
||||
TRY(encoder.encode(serialized_policy_container.csp_list));
|
||||
TRY(encoder.encode(serialized_policy_container.embedder_policy));
|
||||
TRY(encoder.encode(serialized_policy_container.referrer_policy));
|
||||
|
||||
|
@ -24,6 +25,7 @@ ErrorOr<Web::HTML::SerializedPolicyContainer> decode(Decoder& decoder)
|
|||
{
|
||||
Web::HTML::SerializedPolicyContainer serialized_policy_container {};
|
||||
|
||||
serialized_policy_container.csp_list = TRY(decoder.decode<Vector<Web::ContentSecurityPolicy::SerializedPolicy>>());
|
||||
serialized_policy_container.embedder_policy = TRY(decoder.decode<Web::HTML::EmbedderPolicy>());
|
||||
serialized_policy_container.referrer_policy = TRY(decoder.decode<Web::ReferrerPolicy::ReferrerPolicy>());
|
||||
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/ContentSecurityPolicy/SerializedPolicy.h>
|
||||
#include <LibWeb/HTML/EmbedderPolicy.h>
|
||||
#include <LibWeb/ReferrerPolicy/ReferrerPolicy.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
struct SerializedPolicyContainer {
|
||||
Vector<ContentSecurityPolicy::SerializedPolicy> csp_list;
|
||||
EmbedderPolicy embedder_policy;
|
||||
ReferrerPolicy::ReferrerPolicy referrer_policy;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue