mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
Correct event_target for CSP violations (#36887)
All logic is implemented in `report_csp_violations` to avoid pulling in various element-logic into SecurityManager. Update the `icon-blocked.sub.html` WPT test to ensure that the document is the correct target (verified in Firefox and Chrome). Fixes #36806 Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
parent
f3f4cc5500
commit
b6b80d4f6f
56 changed files with 167 additions and 193 deletions
|
@ -4321,7 +4321,7 @@ impl Document {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
self.global().report_csp_violations(violations);
|
self.global().report_csp_violations(violations, Some(el));
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -1040,14 +1040,39 @@ impl From<bool> for EventCancelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EventCancelable> for bool {
|
impl From<EventCancelable> for bool {
|
||||||
fn from(bubbles: EventCancelable) -> Self {
|
fn from(cancelable: EventCancelable) -> Self {
|
||||||
match bubbles {
|
match cancelable {
|
||||||
EventCancelable::Cancelable => true,
|
EventCancelable::Cancelable => true,
|
||||||
EventCancelable::NotCancelable => false,
|
EventCancelable::NotCancelable => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
|
||||||
|
pub(crate) enum EventComposed {
|
||||||
|
Composed,
|
||||||
|
NotComposed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for EventComposed {
|
||||||
|
fn from(boolean: bool) -> Self {
|
||||||
|
if boolean {
|
||||||
|
EventComposed::Composed
|
||||||
|
} else {
|
||||||
|
EventComposed::NotComposed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EventComposed> for bool {
|
||||||
|
fn from(composed: EventComposed) -> Self {
|
||||||
|
match composed {
|
||||||
|
EventComposed::Composed => true,
|
||||||
|
EventComposed::NotComposed => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, JSTraceable, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, JSTraceable, PartialEq)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
|
|
|
@ -448,7 +448,7 @@ impl FetchResponseListener for EventSourceContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,7 @@ use crate::dom::crypto::Crypto;
|
||||||
use crate::dom::dedicatedworkerglobalscope::{
|
use crate::dom::dedicatedworkerglobalscope::{
|
||||||
DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
|
DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
|
||||||
};
|
};
|
||||||
|
use crate::dom::element::Element;
|
||||||
use crate::dom::errorevent::ErrorEvent;
|
use crate::dom::errorevent::ErrorEvent;
|
||||||
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
|
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
|
||||||
use crate::dom::eventsource::EventSource;
|
use crate::dom::eventsource::EventSource;
|
||||||
|
@ -115,6 +116,7 @@ use crate::dom::htmlscriptelement::{ScriptId, SourceCode};
|
||||||
use crate::dom::imagebitmap::ImageBitmap;
|
use crate::dom::imagebitmap::ImageBitmap;
|
||||||
use crate::dom::messageevent::MessageEvent;
|
use crate::dom::messageevent::MessageEvent;
|
||||||
use crate::dom::messageport::MessagePort;
|
use crate::dom::messageport::MessagePort;
|
||||||
|
use crate::dom::node::Node;
|
||||||
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
|
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
|
||||||
use crate::dom::performance::Performance;
|
use crate::dom::performance::Performance;
|
||||||
use crate::dom::performanceobserver::VALID_ENTRY_TYPES;
|
use crate::dom::performanceobserver::VALID_ENTRY_TYPES;
|
||||||
|
@ -2930,7 +2932,7 @@ impl GlobalScope {
|
||||||
|
|
||||||
let (is_js_evaluation_allowed, violations) = csp_list.is_js_evaluation_allowed(source);
|
let (is_js_evaluation_allowed, violations) = csp_list.is_js_evaluation_allowed(source);
|
||||||
|
|
||||||
self.report_csp_violations(violations);
|
self.report_csp_violations(violations, None);
|
||||||
|
|
||||||
is_js_evaluation_allowed == CheckResult::Allowed
|
is_js_evaluation_allowed == CheckResult::Allowed
|
||||||
}
|
}
|
||||||
|
@ -2957,7 +2959,7 @@ impl GlobalScope {
|
||||||
let (result, violations) =
|
let (result, violations) =
|
||||||
csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other);
|
csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other);
|
||||||
|
|
||||||
self.report_csp_violations(violations);
|
self.report_csp_violations(violations, None);
|
||||||
|
|
||||||
result == CheckResult::Blocked
|
result == CheckResult::Blocked
|
||||||
}
|
}
|
||||||
|
@ -3444,8 +3446,13 @@ impl GlobalScope {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://www.w3.org/TR/CSP/#report-violation>
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
|
pub(crate) fn report_csp_violations(
|
||||||
|
&self,
|
||||||
|
violations: Vec<Violation>,
|
||||||
|
element: Option<&Element>,
|
||||||
|
) {
|
||||||
let scripted_caller =
|
let scripted_caller =
|
||||||
unsafe { describe_scripted_caller(*GlobalScope::get_cx()) }.unwrap_or_default();
|
unsafe { describe_scripted_caller(*GlobalScope::get_cx()) }.unwrap_or_default();
|
||||||
for violation in violations {
|
for violation in violations {
|
||||||
|
@ -3471,7 +3478,38 @@ impl GlobalScope {
|
||||||
.line_number(scripted_caller.line)
|
.line_number(scripted_caller.line)
|
||||||
.column_number(scripted_caller.col + 1)
|
.column_number(scripted_caller.col + 1)
|
||||||
.build(self);
|
.build(self);
|
||||||
let task = CSPViolationReportTask::new(self, report);
|
// Step 1: Let global be violation’s global object.
|
||||||
|
// We use `self` as `global`;
|
||||||
|
// Step 2: Let target be violation’s element.
|
||||||
|
let target = element.and_then(|event_target| {
|
||||||
|
// Step 3.1: If target is not null, and global is a Window,
|
||||||
|
// and target’s shadow-including root is not global’s associated Document, set target to null.
|
||||||
|
if let Some(window) = self.downcast::<Window>() {
|
||||||
|
if !window
|
||||||
|
.Document()
|
||||||
|
.upcast::<Node>()
|
||||||
|
.is_shadow_including_inclusive_ancestor_of(event_target.upcast())
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(event_target)
|
||||||
|
});
|
||||||
|
let target = match target {
|
||||||
|
// Step 3.2: If target is null:
|
||||||
|
None => {
|
||||||
|
// Step 3.2.2: If target is a Window, set target to target’s associated Document.
|
||||||
|
if let Some(window) = self.downcast::<Window>() {
|
||||||
|
Trusted::new(window.Document().upcast())
|
||||||
|
} else {
|
||||||
|
// Step 3.2.1: Set target to violation’s global object.
|
||||||
|
Trusted::new(self.upcast())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(event_target) => Trusted::new(event_target.upcast()),
|
||||||
|
};
|
||||||
|
// Step 3: Queue a task to run the following steps:
|
||||||
|
let task = CSPViolationReportTask::new(Trusted::new(self), target, report);
|
||||||
self.task_manager()
|
self.task_manager()
|
||||||
.dom_manipulation_task_source()
|
.dom_manipulation_task_source()
|
||||||
.queue(task);
|
.queue(task);
|
||||||
|
|
|
@ -298,7 +298,7 @@ impl FetchResponseListener for ImageContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -773,7 +773,7 @@ impl FetchResponseListener for PrefetchContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2951,7 +2951,7 @@ impl FetchResponseListener for HTMLMediaElementFetchListener {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -546,7 +546,8 @@ impl FetchResponseListener for ClassicContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
let elem = self.elem.root();
|
||||||
|
global.report_csp_violations(violations, Some(elem.upcast::<Element>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -422,7 +422,7 @@ impl FetchResponseListener for PosterFrameFetchContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -795,7 +795,7 @@ impl FetchResponseListener for ResourceFetchListener {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::dom::bindings::codegen::Bindings::SecurityPolicyViolationEventBinding
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::root::DomRoot;
|
use crate::dom::bindings::root::DomRoot;
|
||||||
use crate::dom::bindings::str::{DOMString, USVString};
|
use crate::dom::bindings::str::{DOMString, USVString};
|
||||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed};
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::script_runtime::CanGc;
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
@ -70,12 +70,14 @@ impl SecurityPolicyViolationEvent {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn new_with_proto(
|
fn new_with_proto(
|
||||||
global: &GlobalScope,
|
global: &GlobalScope,
|
||||||
proto: Option<HandleObject>,
|
proto: Option<HandleObject>,
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
bubbles: EventBubbles,
|
bubbles: EventBubbles,
|
||||||
cancelable: EventCancelable,
|
cancelable: EventCancelable,
|
||||||
|
composed: EventComposed,
|
||||||
init: &SecurityPolicyViolationEventInit,
|
init: &SecurityPolicyViolationEventInit,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
|
@ -83,6 +85,7 @@ impl SecurityPolicyViolationEvent {
|
||||||
{
|
{
|
||||||
let event = ev.upcast::<Event>();
|
let event = ev.upcast::<Event>();
|
||||||
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||||
|
event.set_composed(bool::from(composed));
|
||||||
}
|
}
|
||||||
ev
|
ev
|
||||||
}
|
}
|
||||||
|
@ -92,10 +95,13 @@ impl SecurityPolicyViolationEvent {
|
||||||
type_: Atom,
|
type_: Atom,
|
||||||
bubbles: EventBubbles,
|
bubbles: EventBubbles,
|
||||||
cancelable: EventCancelable,
|
cancelable: EventCancelable,
|
||||||
|
composed: EventComposed,
|
||||||
init: &SecurityPolicyViolationEventInit,
|
init: &SecurityPolicyViolationEventInit,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
Self::new_with_proto(global, None, type_, bubbles, cancelable, init, can_gc)
|
Self::new_with_proto(
|
||||||
|
global, None, type_, bubbles, cancelable, composed, init, can_gc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +121,7 @@ impl SecurityPolicyViolationEventMethods<crate::DomTypeHolder> for SecurityPolic
|
||||||
Atom::from(type_),
|
Atom::from(type_),
|
||||||
EventBubbles::from(init.parent.bubbles),
|
EventBubbles::from(init.parent.bubbles),
|
||||||
EventCancelable::from(init.parent.cancelable),
|
EventCancelable::from(init.parent.cancelable),
|
||||||
|
EventComposed::from(init.parent.composed),
|
||||||
init,
|
init,
|
||||||
can_gc,
|
can_gc,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1075,7 +1075,8 @@ impl FetchResponseListener for ParserContext {
|
||||||
};
|
};
|
||||||
let document = &parser.document;
|
let document = &parser.document;
|
||||||
let global = &document.global();
|
let global = &document.global();
|
||||||
global.report_csp_violations(violations);
|
// TODO(https://github.com/w3c/webappsec-csp/issues/687): Update after spec is resolved
|
||||||
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl TrustedTypePolicyFactory {
|
||||||
(CheckResult::Allowed, Vec::new())
|
(CheckResult::Allowed, Vec::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
|
|
||||||
// Step 2: If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
|
// Step 2: If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
|
||||||
if allowed_by_csp == CheckResult::Blocked {
|
if allowed_by_csp == CheckResult::Blocked {
|
||||||
|
@ -230,7 +230,7 @@ impl TrustedTypePolicyFactory {
|
||||||
.should_sink_type_mismatch_violation_be_blocked_by_csp(
|
.should_sink_type_mismatch_violation_be_blocked_by_csp(
|
||||||
sink, sink_group, &input,
|
sink, sink_group, &input,
|
||||||
);
|
);
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
// Step 6.2: If disposition is “Allowed”, return stringified input and abort further steps.
|
// Step 6.2: If disposition is “Allowed”, return stringified input and abort further steps.
|
||||||
if disposition == CheckResult::Allowed {
|
if disposition == CheckResult::Allowed {
|
||||||
Ok(input)
|
Ok(input)
|
||||||
|
|
|
@ -471,7 +471,7 @@ struct ReportCSPViolationTask {
|
||||||
impl TaskOnce for ReportCSPViolationTask {
|
impl TaskOnce for ReportCSPViolationTask {
|
||||||
fn run_once(self) {
|
fn run_once(self) {
|
||||||
let global = self.websocket.root().global();
|
let global = self.websocket.root().global();
|
||||||
global.report_csp_violations(self.violations);
|
global.report_csp_violations(self.violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ impl FetchResponseListener for XHRContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,7 +313,7 @@ impl FetchResponseListener for FetchContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl FetchResponseListener for LayoutImageContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1277,7 +1277,7 @@ impl FetchResponseListener for ModuleContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -390,7 +390,7 @@ unsafe extern "C" fn content_security_policy_allows(
|
||||||
RuntimeCode::WASM => csp_list.is_wasm_evaluation_allowed(),
|
RuntimeCode::WASM => csp_list.is_wasm_evaluation_allowed(),
|
||||||
};
|
};
|
||||||
|
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
allowed = is_evaluation_allowed == CheckResult::Allowed;
|
allowed = is_evaluation_allowed == CheckResult::Allowed;
|
||||||
});
|
});
|
||||||
allowed
|
allowed
|
||||||
|
|
|
@ -3606,7 +3606,8 @@ impl ScriptThread {
|
||||||
|
|
||||||
fn handle_csp_violations(&self, id: PipelineId, _: RequestId, violations: Vec<csp::Violation>) {
|
fn handle_csp_violations(&self, id: PipelineId, _: RequestId, violations: Vec<csp::Violation>) {
|
||||||
if let Some(global) = self.documents.borrow().find_global(id) {
|
if let Some(global) = self.documents.borrow().find_global(id) {
|
||||||
global.report_csp_violations(violations);
|
// TODO(https://github.com/w3c/webappsec-csp/issues/687): Update after spec is resolved
|
||||||
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@ use crate::dom::bindings::codegen::Bindings::SecurityPolicyViolationEventBinding
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::refcounted::Trusted;
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
use crate::dom::bindings::reflector::DomGlobal;
|
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed};
|
||||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
|
||||||
use crate::dom::eventtarget::EventTarget;
|
use crate::dom::eventtarget::EventTarget;
|
||||||
use crate::dom::securitypolicyviolationevent::SecurityPolicyViolationEvent;
|
use crate::dom::securitypolicyviolationevent::SecurityPolicyViolationEvent;
|
||||||
use crate::dom::types::GlobalScope;
|
use crate::dom::types::GlobalScope;
|
||||||
|
@ -23,6 +22,7 @@ use crate::script_runtime::CanGc;
|
||||||
use crate::task::TaskOnce;
|
use crate::task::TaskOnce;
|
||||||
|
|
||||||
pub(crate) struct CSPViolationReportTask {
|
pub(crate) struct CSPViolationReportTask {
|
||||||
|
global: Trusted<GlobalScope>,
|
||||||
event_target: Trusted<EventTarget>,
|
event_target: Trusted<EventTarget>,
|
||||||
violation_report: SecurityPolicyViolationReport,
|
violation_report: SecurityPolicyViolationReport,
|
||||||
}
|
}
|
||||||
|
@ -159,28 +159,31 @@ impl CSPViolationReportBuilder {
|
||||||
|
|
||||||
impl CSPViolationReportTask {
|
impl CSPViolationReportTask {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
global: &GlobalScope,
|
global: Trusted<GlobalScope>,
|
||||||
report: SecurityPolicyViolationReport,
|
event_target: Trusted<EventTarget>,
|
||||||
|
violation_report: SecurityPolicyViolationReport,
|
||||||
) -> CSPViolationReportTask {
|
) -> CSPViolationReportTask {
|
||||||
CSPViolationReportTask {
|
CSPViolationReportTask {
|
||||||
violation_report: report,
|
global,
|
||||||
event_target: Trusted::new(global.upcast::<EventTarget>()),
|
event_target,
|
||||||
|
violation_report,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fire_violation_event(self, can_gc: CanGc) {
|
fn fire_violation_event(self, can_gc: CanGc) {
|
||||||
let target = self.event_target.root();
|
|
||||||
let global = &target.global();
|
|
||||||
let event = SecurityPolicyViolationEvent::new(
|
let event = SecurityPolicyViolationEvent::new(
|
||||||
global,
|
&self.global.root(),
|
||||||
Atom::from("securitypolicyviolation"),
|
Atom::from("securitypolicyviolation"),
|
||||||
EventBubbles::Bubbles,
|
EventBubbles::Bubbles,
|
||||||
EventCancelable::Cancelable,
|
EventCancelable::Cancelable,
|
||||||
|
EventComposed::Composed,
|
||||||
&self.violation_report.convert(),
|
&self.violation_report.convert(),
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
|
|
||||||
event.upcast::<Event>().fire(&target, can_gc);
|
event
|
||||||
|
.upcast::<Event>()
|
||||||
|
.fire(&self.event_target.root(), can_gc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -286,7 +286,7 @@ impl FetchResponseListener for StylesheetContext {
|
||||||
|
|
||||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||||
let global = &self.resource_timing_global();
|
let global = &self.resource_timing_global();
|
||||||
global.report_csp_violations(violations);
|
global.report_csp_violations(violations, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
tests/wpt/meta/MANIFEST.json
vendored
9
tests/wpt/meta/MANIFEST.json
vendored
|
@ -569742,7 +569742,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"icon-blocked.sub.html": [
|
"icon-blocked.sub.html": [
|
||||||
"cc882347a1ac7b595275c2263ef266826e6f07bd",
|
"4c39e5dec735c10635a603356367610d3aad3fa2",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
|
@ -569797,6 +569797,13 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"img-src-targeting.html": [
|
||||||
|
"3b4fe7c690b0b980a9626de0deb02c8950f5d4a0",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"img-src-wildcard-allowed.html": [
|
"img-src-wildcard-allowed.html": [
|
||||||
"050a4d14100bb1ef719d6700bfbd37a97424af59",
|
"050a4d14100bb1ef719d6700bfbd37a97424af59",
|
||||||
[
|
[
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
[script-tag.http.html]
|
[script-tag.http.html]
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-http origin and keep-origin redirection from http context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-http origin and no-redirect redirection from http context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-http origin and swap-origin redirection from http context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.]
|
[Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
[script-tag.https.html]
|
[script-tag.https.html]
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-https origin and keep-origin redirection from https context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-https origin and no-redirect redirection from https context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-https origin and swap-origin redirection from https context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.]
|
[Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
[script-tag.http.html]
|
[script-tag.http.html]
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-http origin and keep-origin redirection from http context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-http origin and no-redirect redirection from http context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-http origin and swap-origin redirection from http context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.]
|
[Content Security Policy: Expects blocked for script-tag to same-http origin and swap-origin redirection from http context.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
[script-tag.https.html]
|
[script-tag.https.html]
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-https origin and keep-origin redirection from https context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-https origin and no-redirect redirection from https context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to cross-https origin and swap-origin redirection from https context.: securitypolicyviolation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.]
|
[Content Security Policy: Expects blocked for script-tag to same-https origin and swap-origin redirection from https context.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
[to-javascript-url-script-src.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[<iframe src='javascript:'> blocked without 'unsafe-inline'.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[<iframe> navigated to 'javascript:' blocked without 'unsafe-inline'.]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[<iframe src='...'> with 'unsafe-inline' navigated to 'javascript:' blocked in this document]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[<iframe src='...'> without 'unsafe-inline' navigated to 'javascript:' blocked in this document.]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,11 +1,5 @@
|
||||||
[report-original-url.sub.html]
|
[report-original-url.sub.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Direct block, same-origin = full URL in report]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[Direct block, cross-origin = full URL in report]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[Block after redirect, same-origin = original URL in report]
|
[Block after redirect, same-origin = original URL in report]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[script-src-report-only-policy-works-with-hash-policy.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Test that the securitypolicyviolation event is fired]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[blockeduri-eval.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Eval violations have a blockedURI of 'eval']
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,4 +1,3 @@
|
||||||
[blockeduri-inline.html]
|
[blockeduri-inline.html]
|
||||||
expected: TIMEOUT
|
|
||||||
[Inline violations have a blockedURI of 'inline']
|
[Inline violations have a blockedURI of 'inline']
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
|
@ -1,13 +1,3 @@
|
||||||
[blockeduri-ws-wss-scheme.html]
|
[blockeduri-ws-wss-scheme.html]
|
||||||
expected: TIMEOUT
|
|
||||||
[ws]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[wss]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cross-origin]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[redirect]
|
[redirect]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[linenumber.tentative.html]
|
[linenumber.tentative.html]
|
||||||
expected: TIMEOUT
|
|
||||||
[linenumber]
|
[linenumber]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
[script-sample-no-opt-in.html]
|
[script-sample-no-opt-in.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Inline script should not have a sample.]
|
[JavaScript URLs in iframes should not have a sample.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Inline event handlers should not have a sample.]
|
[Inline event handlers should not have a sample.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[JavaScript URLs in iframes should not have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[eval()-alikes should not have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,19 +1,7 @@
|
||||||
[script-sample.html]
|
[script-sample.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Inline script should have a sample.]
|
[JavaScript URLs in iframes should have a sample.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Inline event handlers should have a sample.]
|
[Inline event handlers should have a sample.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[JavaScript URLs in iframes should have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[eval() should have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[setInterval() should have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[setTimeout() should have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[source-file-blob-scheme.html]
|
[source-file-blob-scheme.html]
|
||||||
expected: TIMEOUT
|
|
||||||
[Violations from data:-URL scripts have a sourceFile of 'blob']
|
[Violations from data:-URL scripts have a sourceFile of 'blob']
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[source-file-data-scheme.html]
|
[source-file-data-scheme.html]
|
||||||
expected: TIMEOUT
|
|
||||||
[Violations from data:-URL scripts have a sourceFile of 'data']
|
[Violations from data:-URL scripts have a sourceFile of 'data']
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
[style-sample-no-opt-in.html]
|
[style-sample-no-opt-in.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Inline style blocks should not have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[Inline style attributes should not have a sample.]
|
[Inline style attributes should not have a sample.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
[style-sample.html]
|
[style-sample.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Inline style blocks should have a sample.]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[Inline style attributes should have a sample.]
|
[Inline style attributes should have a sample.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
|
@ -4,13 +4,10 @@
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
||||||
[Inline violations target the right element.]
|
[Inline violations target the right element.]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
[Correct targeting inside shadow tree (inline handler).]
|
[Correct targeting inside shadow tree (inline handler).]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Correct targeting inside shadow tree (style).]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.]
|
[Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-hash-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-imported-style-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-injected-inline-style-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-injected-stylesheet-blocked.sub.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-inline-style-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,7 +1,4 @@
|
||||||
[style-src-inline-style-nonce-blocked-error-event.html]
|
[style-src-inline-style-nonce-blocked-error-event.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Test that paragraph remains unmodified and error events received.]
|
[Test that paragraph remains unmodified and error events received.]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-inline-style-nonce-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-none-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,4 +0,0 @@
|
||||||
[style-src-stylesheet-nonce-blocked.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Should fire a securitypolicyviolation event]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,2 +1,10 @@
|
||||||
[report.https.sub.html]
|
[report.https.sub.html]
|
||||||
expected: TIMEOUT
|
expected: ERROR
|
||||||
|
[same-origin report]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[same-site report]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[cross-site report]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[default-policy.html]
|
[default-policy.html]
|
||||||
expected: TIMEOUT
|
expected: OK
|
||||||
[Count SecurityPolicyViolation events.]
|
[Count SecurityPolicyViolation events.]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
[div.innerHTML no default policy]
|
[div.innerHTML no default policy]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[empty-default-policy.html]
|
[empty-default-policy.html]
|
||||||
expected: TIMEOUT
|
expected: OK
|
||||||
[Count SecurityPolicyViolation events.]
|
[Count SecurityPolicyViolation events.]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
[div.innerHTML default]
|
[div.innerHTML default]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[script-src-blocks-wasm.tentative.sub.html]
|
|
||||||
[Importing a WebAssembly module should be guarded by script-src CSP.]
|
|
||||||
expected: FAIL
|
|
|
@ -12,6 +12,7 @@
|
||||||
var t_spv = async_test("Test that spv event is fired");
|
var t_spv = async_test("Test that spv event is fired");
|
||||||
window.addEventListener("securitypolicyviolation", t_spv.step_func_done(function(e) {
|
window.addEventListener("securitypolicyviolation", t_spv.step_func_done(function(e) {
|
||||||
assert_equals(e.violatedDirective, 'img-src');
|
assert_equals(e.violatedDirective, 'img-src');
|
||||||
|
assert_equals(e.target, document);
|
||||||
assert_true(e.blockedURI.endsWith('/support/fail.png'));
|
assert_true(e.blockedURI.endsWith('/support/fail.png'));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
24
tests/wpt/tests/content-security-policy/img-src/img-src-targeting.html
vendored
Normal file
24
tests/wpt/tests/content-security-policy/img-src/img-src-targeting.html
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="img-src 'none';">
|
||||||
|
<script src='/resources/testharness.js'></script>
|
||||||
|
<script src='/resources/testharnessreport.js'></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Check that img-src sets correct target</p>
|
||||||
|
<script>
|
||||||
|
var t = async_test("Test that image does not load");
|
||||||
|
var t_spv = async_test("Test that spv event is fired");
|
||||||
|
window.addEventListener("securitypolicyviolation", t_spv.step_func_done(function(e) {
|
||||||
|
assert_equals(e.violatedDirective, 'img-src');
|
||||||
|
assert_equals(e.target, document);
|
||||||
|
assert_true(e.blockedURI.endsWith('/support/fail.png'));
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
<img src='/content-security-policy/support/fail.png'
|
||||||
|
onload='t.step(function() { assert_unreached("Image should not have loaded"); t.done(); });'
|
||||||
|
onerror='t.done();'>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue