mirror of
https://github.com/servo/servo.git
synced 2025-07-22 14:53:49 +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
|
||||
}
|
||||
|
|
|
@ -1040,14 +1040,39 @@ impl From<bool> for EventCancelable {
|
|||
}
|
||||
|
||||
impl From<EventCancelable> for bool {
|
||||
fn from(bubbles: EventCancelable) -> Self {
|
||||
match bubbles {
|
||||
fn from(cancelable: EventCancelable) -> Self {
|
||||
match cancelable {
|
||||
EventCancelable::Cancelable => true,
|
||||
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)]
|
||||
#[repr(u16)]
|
||||
#[derive(MallocSizeOf)]
|
||||
|
|
|
@ -448,7 +448,7 @@ impl FetchResponseListener for EventSourceContext {
|
|||
|
||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||
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::{
|
||||
DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
|
||||
};
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::errorevent::ErrorEvent;
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
|
||||
use crate::dom::eventsource::EventSource;
|
||||
|
@ -115,6 +116,7 @@ use crate::dom::htmlscriptelement::{ScriptId, SourceCode};
|
|||
use crate::dom::imagebitmap::ImageBitmap;
|
||||
use crate::dom::messageevent::MessageEvent;
|
||||
use crate::dom::messageport::MessagePort;
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
|
||||
use crate::dom::performance::Performance;
|
||||
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);
|
||||
|
||||
self.report_csp_violations(violations);
|
||||
self.report_csp_violations(violations, None);
|
||||
|
||||
is_js_evaluation_allowed == CheckResult::Allowed
|
||||
}
|
||||
|
@ -2957,7 +2959,7 @@ impl GlobalScope {
|
|||
let (result, violations) =
|
||||
csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other);
|
||||
|
||||
self.report_csp_violations(violations);
|
||||
self.report_csp_violations(violations, None);
|
||||
|
||||
result == CheckResult::Blocked
|
||||
}
|
||||
|
@ -3444,8 +3446,13 @@ impl GlobalScope {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/CSP/#report-violation>
|
||||
#[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 =
|
||||
unsafe { describe_scripted_caller(*GlobalScope::get_cx()) }.unwrap_or_default();
|
||||
for violation in violations {
|
||||
|
@ -3471,7 +3478,38 @@ impl GlobalScope {
|
|||
.line_number(scripted_caller.line)
|
||||
.column_number(scripted_caller.col + 1)
|
||||
.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()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(task);
|
||||
|
|
|
@ -298,7 +298,7 @@ impl FetchResponseListener for ImageContext {
|
|||
|
||||
fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<csp::Violation>) {
|
||||
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>) {
|
||||
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>) {
|
||||
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>) {
|
||||
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>) {
|
||||
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>) {
|
||||
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::root::DomRoot;
|
||||
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::script_runtime::CanGc;
|
||||
|
||||
|
@ -70,12 +70,14 @@ impl SecurityPolicyViolationEvent {
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
composed: EventComposed,
|
||||
init: &SecurityPolicyViolationEventInit,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
|
@ -83,6 +85,7 @@ impl SecurityPolicyViolationEvent {
|
|||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
|
||||
event.set_composed(bool::from(composed));
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
@ -92,10 +95,13 @@ impl SecurityPolicyViolationEvent {
|
|||
type_: Atom,
|
||||
bubbles: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
composed: EventComposed,
|
||||
init: &SecurityPolicyViolationEventInit,
|
||||
can_gc: CanGc,
|
||||
) -> 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_),
|
||||
EventBubbles::from(init.parent.bubbles),
|
||||
EventCancelable::from(init.parent.cancelable),
|
||||
EventComposed::from(init.parent.composed),
|
||||
init,
|
||||
can_gc,
|
||||
)
|
||||
|
|
|
@ -1075,7 +1075,8 @@ impl FetchResponseListener for ParserContext {
|
|||
};
|
||||
let document = &parser.document;
|
||||
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())
|
||||
};
|
||||
|
||||
global.report_csp_violations(violations);
|
||||
global.report_csp_violations(violations, None);
|
||||
|
||||
// Step 2: If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
|
||||
if allowed_by_csp == CheckResult::Blocked {
|
||||
|
@ -230,7 +230,7 @@ impl TrustedTypePolicyFactory {
|
|||
.should_sink_type_mismatch_violation_be_blocked_by_csp(
|
||||
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.
|
||||
if disposition == CheckResult::Allowed {
|
||||
Ok(input)
|
||||
|
|
|
@ -471,7 +471,7 @@ struct ReportCSPViolationTask {
|
|||
impl TaskOnce for ReportCSPViolationTask {
|
||||
fn run_once(self) {
|
||||
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>) {
|
||||
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>) {
|
||||
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>) {
|
||||
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>) {
|
||||
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(),
|
||||
};
|
||||
|
||||
global.report_csp_violations(violations);
|
||||
global.report_csp_violations(violations, None);
|
||||
allowed = is_evaluation_allowed == CheckResult::Allowed;
|
||||
});
|
||||
allowed
|
||||
|
|
|
@ -3606,7 +3606,8 @@ impl ScriptThread {
|
|||
|
||||
fn handle_csp_violations(&self, id: PipelineId, _: RequestId, violations: Vec<csp::Violation>) {
|
||||
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::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomGlobal;
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::securitypolicyviolationevent::SecurityPolicyViolationEvent;
|
||||
use crate::dom::types::GlobalScope;
|
||||
|
@ -23,6 +22,7 @@ use crate::script_runtime::CanGc;
|
|||
use crate::task::TaskOnce;
|
||||
|
||||
pub(crate) struct CSPViolationReportTask {
|
||||
global: Trusted<GlobalScope>,
|
||||
event_target: Trusted<EventTarget>,
|
||||
violation_report: SecurityPolicyViolationReport,
|
||||
}
|
||||
|
@ -159,28 +159,31 @@ impl CSPViolationReportBuilder {
|
|||
|
||||
impl CSPViolationReportTask {
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
report: SecurityPolicyViolationReport,
|
||||
global: Trusted<GlobalScope>,
|
||||
event_target: Trusted<EventTarget>,
|
||||
violation_report: SecurityPolicyViolationReport,
|
||||
) -> CSPViolationReportTask {
|
||||
CSPViolationReportTask {
|
||||
violation_report: report,
|
||||
event_target: Trusted::new(global.upcast::<EventTarget>()),
|
||||
global,
|
||||
event_target,
|
||||
violation_report,
|
||||
}
|
||||
}
|
||||
|
||||
fn fire_violation_event(self, can_gc: CanGc) {
|
||||
let target = self.event_target.root();
|
||||
let global = &target.global();
|
||||
let event = SecurityPolicyViolationEvent::new(
|
||||
global,
|
||||
&self.global.root(),
|
||||
Atom::from("securitypolicyviolation"),
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
EventComposed::Composed,
|
||||
&self.violation_report.convert(),
|
||||
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>) {
|
||||
let global = &self.resource_timing_global();
|
||||
global.report_csp_violations(violations);
|
||||
global.report_csp_violations(violations, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue