mirror of
https://github.com/lexmount/moli.git
synced 2026-10-04 16:00:47 +00:00
@@ -831,12 +831,15 @@ impl JsContextHost {
|
||||
if report_only_violation.is_none() && enforced_violation.is_none() {
|
||||
return true;
|
||||
}
|
||||
if include_call_location {
|
||||
let (line_number, column_number) = current_script_call_location(scope);
|
||||
if include_call_location
|
||||
&& let Some((source_file, line_number, column_number)) =
|
||||
current_script_violation_location(scope)
|
||||
{
|
||||
for violation in [&mut report_only_violation, &mut enforced_violation]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
violation.source_file = source_file.clone();
|
||||
violation.line_number = line_number;
|
||||
violation.column_number = column_number;
|
||||
}
|
||||
@@ -1264,14 +1267,21 @@ impl JsContextHost {
|
||||
}
|
||||
}
|
||||
|
||||
fn current_script_call_location(scope: &v8::PinScope<'_, '_>) -> (i32, i32) {
|
||||
let Some(stack) = v8::StackTrace::current_stack_trace(scope, 1) else {
|
||||
return (0, 0);
|
||||
};
|
||||
let Some(frame) = stack.get_frame(scope, 0) else {
|
||||
return (0, 0);
|
||||
};
|
||||
let line = i32::try_from(frame.get_line_number()).unwrap_or(0).max(0);
|
||||
let column = i32::try_from(frame.get_column()).unwrap_or(0).max(0);
|
||||
(line, column)
|
||||
fn current_script_violation_location(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
) -> Option<(String, i32, i32)> {
|
||||
let stack = v8::StackTrace::current_stack_trace(scope, 1)?;
|
||||
let frame = stack.get_frame(scope, 0)?;
|
||||
let source_file = frame
|
||||
.get_script_name_or_source_url(scope)
|
||||
.map(|source| source.to_rust_string_lossy(scope))
|
||||
.map(|source| {
|
||||
crate::content_security_policy::content_security_policy_source_file_for_report(&source)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let line_number = i32::try_from(frame.get_line_number())
|
||||
.unwrap_or_default()
|
||||
.max(0);
|
||||
let column_number = i32::try_from(frame.get_column()).unwrap_or_default().max(0);
|
||||
Some((source_file, line_number, column_number))
|
||||
}
|
||||
|
||||
@@ -1062,3 +1062,80 @@ async fn prepared_parser_inline_script_csp_blocks_before_v8_execution_and_report
|
||||
r#"[{"blockedURI":"inline","effectiveDirective":"script-src-elem","lineNumber":0,"columnNumber":0}]"#
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn eval_csp_violation_reports_external_script_scheme_and_call_location() {
|
||||
let source = r#"
|
||||
globalThis.__evalCspErrorName = "";
|
||||
try {
|
||||
eval("globalThis.__blockedEvalRan = true");
|
||||
} catch (error) {
|
||||
globalThis.__evalCspErrorName = error.name;
|
||||
}
|
||||
"#;
|
||||
|
||||
for (index, (script_url, expected_source_file)) in [
|
||||
("data:text/javascript,eval-source", "data"),
|
||||
(
|
||||
"blob:https://eval-source-location.test/00000000-0000-0000-0000-000000000000",
|
||||
"blob",
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let mut vm = new_storage_test_vm("https://eval-source-location.test/page.html");
|
||||
vm.set_response_content_security_policies(&["script-src data: blob:".to_owned()]);
|
||||
vm.eval(
|
||||
r#"
|
||||
globalThis.__evalCspViolations = [];
|
||||
document.addEventListener("securitypolicyviolation", event => {
|
||||
globalThis.__evalCspViolations.push({
|
||||
blockedURI: event.blockedURI,
|
||||
sourceFile: event.sourceFile,
|
||||
linePositive: event.lineNumber > 0,
|
||||
columnPositive: event.columnNumber > 0,
|
||||
});
|
||||
});
|
||||
"#,
|
||||
)
|
||||
.expect("eval CSP observer should install");
|
||||
|
||||
let script_url = Url::parse(script_url).expect("external script URL");
|
||||
let script = PreparedScript {
|
||||
position: index,
|
||||
node_id: NodeId::new(index + 1),
|
||||
kind: ScriptKind::Classic,
|
||||
mode: ScriptMode::Async,
|
||||
source_kind: ScriptSourceKind::External,
|
||||
fetch_metadata: crate::planning::ScriptFetchMetadata::default(),
|
||||
source: ScriptSource::External,
|
||||
url: script_url.clone(),
|
||||
base_url: script_url,
|
||||
initiator_url: Url::parse("https://eval-source-location.test/page.html")
|
||||
.expect("initiator URL"),
|
||||
host_script_handle: None,
|
||||
};
|
||||
|
||||
vm.execute_loaded_prepared_script_source(&script, source, None)
|
||||
.await
|
||||
.expect("external script with blocked eval should complete");
|
||||
assert_eq!(
|
||||
drain_pre_domcontentloaded_non_script_page_tasks_for_test(&mut vm),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
vm.eval(
|
||||
r#"JSON.stringify({
|
||||
errorName: globalThis.__evalCspErrorName,
|
||||
ran: globalThis.__blockedEvalRan === true,
|
||||
violations: globalThis.__evalCspViolations,
|
||||
})"#
|
||||
)
|
||||
.expect("eval CSP result should remain observable"),
|
||||
format!(
|
||||
r#"{{"errorName":"EvalError","ran":false,"violations":[{{"blockedURI":"eval","sourceFile":"{expected_source_file}","linePositive":true,"columnPositive":true}}]}}"#
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user