From 481fb63acf51994dfadd5c472b5672b7110be869 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Wed, 12 Nov 2025 13:28:13 +0200 Subject: [PATCH] fix(cef): inject init scripts CSP only if it was set in request headers (#14451) --- .../src/cef_impl/request_handler.rs | 80 ++++++++----------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs b/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs index a2459d769..9db8d47c5 100644 --- a/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs +++ b/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs @@ -28,11 +28,11 @@ use crate::cef_impl::Context; use super::CefInitScript; fn csp_inject_initialization_scripts_hashes( - existing_csp: Option<&str>, + existing_csp: String, initialization_scripts: &[CefInitScript], -) -> Option { +) -> String { if initialization_scripts.is_empty() { - return existing_csp.map(|s| s.to_string()); + return existing_csp; } // For custom schemes, include ALL script hashes (we inject all scripts into HTML) @@ -43,34 +43,23 @@ fn csp_inject_initialization_scripts_hashes( .collect(); if script_hashes.is_empty() { - return existing_csp.map(|s| s.to_string()); + return existing_csp; } - let new_csp = if let Some(existing_csp) = existing_csp { - // Parse CSP using tauri-utils - let mut csp_map: std::collections::HashMap = - Csp::Policy(existing_csp.to_string()).into(); + // Parse CSP using tauri-utils + let mut csp_map: std::collections::HashMap = + Csp::Policy(existing_csp.to_string()).into(); - // Update or create script-src directive with script hashes - let script_src = csp_map - .entry("script-src".to_string()) - .or_insert_with(|| CspDirectiveSources::List(vec!["'self'".to_string()])); + // Update or create script-src directive with script hashes + let script_src = csp_map + .entry("script-src".to_string()) + .or_insert_with(|| CspDirectiveSources::List(vec!["'self'".to_string()])); - // Extend with script hashes - script_src.extend(script_hashes); + // Extend with script hashes + script_src.extend(script_hashes); - // Convert back to CSP string - Csp::DirectiveMap(csp_map).to_string() - } else { - // No existing CSP, create new one with just script-src - let mut csp_map = std::collections::HashMap::new(); - let mut script_src = CspDirectiveSources::List(vec!["'self'".to_string()]); - script_src.extend(script_hashes); - csp_map.insert("script-src".to_string(), script_src); - Csp::DirectiveMap(csp_map).to_string() - }; - - Some(new_csp) + // Convert back to CSP string + Csp::DirectiveMap(csp_map).to_string() } /// Helper function to inject initialization scripts into HTML body @@ -222,7 +211,23 @@ wrap_resource_handler! { body_bytes }; - let response = http::Response::from_parts(parts, Cursor::new(modified_body)); + let mut response = http::Response::from_parts(parts, Cursor::new(modified_body)); + + + let csp = response + .headers_mut() + .get_mut(CONTENT_SECURITY_POLICY); + + if let Some(csp) = csp { + let csp_string = csp.to_str().unwrap().to_string(); + let new_csp = csp_inject_initialization_scripts_hashes( + csp_string, + &initialization_scripts, + ); + *csp = HeaderValue::from_str(&new_csp).unwrap(); + } + + response_store.into_owned().borrow_mut().replace(response); let callback = callback.into_owned(); @@ -284,37 +289,18 @@ wrap_resource_handler! { response.set_status(response_data.status().as_u16() as i32); let mut content_type = None; - let mut csp_header: Option = None; // First pass: collect CSP header and set other headers for (name, value) in response_data.headers() { let Ok(value) = value.to_str() else { continue; }; - if name == CONTENT_SECURITY_POLICY { - csp_header = Some(value.to_string()); - } else { - response.set_header_by_name(Some(&name.as_str().into()), Some(&value.into()), 0); - } + response.set_header_by_name(Some(&name.as_str().into()), Some(&value.into()), 0); if name == CONTENT_TYPE { content_type.replace(value.to_string()); } } - let new_csp = csp_inject_initialization_scripts_hashes( - csp_header.as_deref(), - &self.initialization_scripts, - ); - - if let Some(new_csp) = new_csp { - let csp_header_name = CefString::from(CONTENT_SECURITY_POLICY.as_str()); - response.set_header_by_name( - Some(&csp_header_name), - Some(&CefString::from(new_csp.as_str())), - 0, - ); - } - let mime_type = content_type .as_ref() .and_then(|t| t.split(';').next())