Skip to content

Commit

Permalink
LibWeb: Stub in CSP List
Browse files Browse the repository at this point in the history
Working backwards from
https://html.spec.whatwg.org/multipage/semantics.html#update-a-style-block

One of the steps in the above algorithm is
https://w3c.github.io/webappsec-csp/#should-block-inline

In implementing Should element’s inline type behavior be blocked
by Content Security Policy?, add class declarations for
Directives, Policy's, and CSP Lists
  • Loading branch information
noahmbright committed Oct 15, 2024
1 parent c4f7361 commit 8f3b531
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
45 changes: 45 additions & 0 deletions Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,54 @@
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/ShadowRoot.h>
#include <LibWeb/DOM/StyleElementUtils.h>
#include <LibWeb/HTML/PolicyContainers.h>
#include <LibWeb/Infra/Strings.h>

namespace Web::DOM {

// https://w3c.github.io/webappsec-csp/#should-block-inline
static ErrorOr<ShouldBeBlockedByContentSecurityPolicy> should_elements_inline_type_behavior_be_blocked_by_content_security_policy(
Element const& element, InlineType type, String const& source)
{
dbgln("FIXME: Implement should_elements_inline_type_behavior_be_blocked_by_content_security_policy");
(void)source;
(void)type;

// FIXME: 1. Assert: element is not null.

// 2. Let result be "Allowed".
auto result = ShouldBeBlockedByContentSecurityPolicy::Allowed;

// FIXME: 3. For each policy of element’s Document's global object’s CSP list:
auto& documents_global_object = element.realm().global_object();
for (auto const& policy : HTML::retrieve_the_csp_list_of_an_object(documents_global_object).value()) {
// FIXME: 1. For each directive of policy’s directive set:
for (auto directive : policy.directive_set) {
// FIXME: 1. If directive’s inline check returns "Allowed" when executed upon element, type, policy and source, skip to the next directive.

// FIXME: 2. Let directive-name be the result of executing § 6.8.2 Get the effective directive for inline checks on type.

// FIXME: 3. Otherwise, let violation be the result of executing § 2.4.1 Create a violation object for global, policy, and directive on the current settings object’s global object, policy, and directive-name.

// FIXME: 4. Set violation’s resource to "inline".

// FIXME: 5. Set violation’s element to element.

// FIXME: 6. If directive’s value contains the expression "'report-sample'", then set violation’s sample to the substring of source containing its first 40 characters.

// FIXME: 7. Execute § 5.5 Report a violation on violation.

// FIXME: 8. If policy’s disposition is "enforce", then set result to "Blocked".
//
}
}
// 4. Return result.
return result;
}

// The user agent must run the "update a style block" algorithm whenever one of the following conditions occur:
// FIXME: The element is popped off the stack of open elements of an HTML parser or XML parser.
//
Expand Down Expand Up @@ -51,6 +93,9 @@ void StyleElementUtils::update_a_style_block(DOM::Element& style_element)
return;

// FIXME: 5. If the Should element's inline behavior be blocked by Content Security Policy? algorithm returns "Blocked" when executed upon the style element, "style", and the style element's child text content, then return. [CSP]
if (should_elements_inline_type_behavior_be_blocked_by_content_security_policy(style_element, InlineType::Style, style_element.child_text_content()).value()
== ShouldBeBlockedByContentSecurityPolicy::Blocked)
return;

// FIXME: This is a bit awkward, as the spec doesn't actually tell us when to parse the CSS text,
// so we just do it here and pass the parsed sheet to create_a_css_style_sheet().
Expand Down
13 changes: 13 additions & 0 deletions Userland/Libraries/LibWeb/DOM/StyleElementUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@

namespace Web::DOM {

// https://w3c.github.io/webappsec-csp/#should-block-inline
enum class InlineType {
Script,
ScriptAttribute,
Style,
StyleAttribute
};

enum class ShouldBeBlockedByContentSecurityPolicy {
Allowed,
Blocked
};

class StyleElementUtils {
public:
void update_a_style_block(DOM::Element& style_element);
Expand Down
37 changes: 37 additions & 0 deletions Userland/Libraries/LibWeb/HTML/Policy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2024, Noah Bright <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/HashTable.h>
#include <AK/String.h>
#include <LibWeb/HTML/Origin.h>

// https://w3c.github.io/webappsec-csp/#framework-policy
namespace Web::HTML {

enum class PolicyDisposition {
Enforce,
Report
};

enum class PolicySource {
Head,
Meta
};

// https://w3c.github.io/webappsec-csp/#content-security-policy-object
struct Policy {
// https://w3c.github.io/webappsec-csp/#directives
OrderedHashMap<String, Optional<HashTable<String>>> directive_set;
PolicyDisposition disposition;
PolicySource source;
HTML::Origin self_origin;
};

using CSPList = Vector<Policy>;

}
25 changes: 25 additions & 0 deletions Userland/Libraries/LibWeb/HTML/PolicyContainers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,32 @@

#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/PolicyContainers.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WorkerGlobalScope.h>

namespace Web::HTML {

// https://w3c.github.io/webappsec-csp/#get-csp-of-object
Optional<CSPList&> retrieve_the_csp_list_of_an_object(JS::Object const& object)
{
// 1. If object is a Document return object’s policy container's CSP list.
if (is<DOM::Document>(object))
return verify_cast<DOM::Document>(object).policy_container().csp_list;

// FIXME: 2. If object is a Window or a WorkerGlobalScope or a WorkletGlobalScope, return environment settings object’s policy container's CSP list.
// WorkletGlobalScope not yet defined
if (is<Window>(object))
return verify_cast<Window>(object).associated_document().policy_container().csp_list;

if (is<WorkerGlobalScope>(object))
return verify_cast<WorkerGlobalScope>(object).policy_container().csp_list;

// 3. Return null.
return {};
}
}

namespace IPC {

Expand Down
8 changes: 7 additions & 1 deletion Userland/Libraries/LibWeb/HTML/PolicyContainers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#pragma once

#include <LibIPC/Forward.h>
#include <LibJS/Runtime/Object.h>
#include <LibWeb/HTML/EmbedderPolicy.h>
#include <LibWeb/HTML/Policy.h>
#include <LibWeb/ReferrerPolicy/ReferrerPolicy.h>

namespace Web::HTML {
Expand All @@ -16,7 +18,8 @@ namespace Web::HTML {
// A policy container is a struct containing policies that apply to a Document, a WorkerGlobalScope, or a WorkletGlobalScope. It has the following items:
struct PolicyContainer {
// 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.
CSPList 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.
Expand All @@ -27,6 +30,9 @@ struct PolicyContainer {
ReferrerPolicy::ReferrerPolicy referrer_policy { ReferrerPolicy::DEFAULT_REFERRER_POLICY };
};

// https://w3c.github.io/webappsec-csp/#get-csp-of-object
Optional<CSPList> retrieve_the_csp_list_of_an_object(JS::Object const&);

}

namespace IPC {
Expand Down

0 comments on commit 8f3b531

Please sign in to comment.