mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 15:56:51 +00:00
fix(core): SHA256 hash for JS scripts CSP on Windows (#14265)
* fix(core): SHA256 hash for JS scripts CSP on Windows we hash JS scripts as SHA256 for the Content-Security-Policy (CSP) header. The isolation pattern is broken on Windows due to the hash including carriage return characters, which are not processed when the webview checks the script hash to see if the CSP allows the script. * fmt, clippy
This commit is contained in:
parent
c5008b829d
commit
7b0d4e7322
5
.changes/fix-csp-windows.md
Normal file
5
.changes/fix-csp-windows.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-codegen": patch:bug
|
||||
---
|
||||
|
||||
Fix JavaScript SHA256 hash generation on Windows not ignoring carriage return characters.
|
||||
5
.changes/normalize_script_for_csp.md
Normal file
5
.changes/normalize_script_for_csp.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-utils": patch:feat
|
||||
---
|
||||
|
||||
Added `html::normalize_script_for_csp`.
|
||||
@ -50,7 +50,9 @@ fn inject_script_hashes(document: &NodeRef, key: &AssetKey, csp_hashes: &mut Csp
|
||||
for inline_script_el in inline_script_elements {
|
||||
let script = inline_script_el.as_node().text_contents();
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&script);
|
||||
hasher.update(tauri_utils::html::normalize_script_for_csp(
|
||||
script.as_bytes(),
|
||||
));
|
||||
let hash = hasher.finalize();
|
||||
scripts.push(format!(
|
||||
"'sha256-{}'",
|
||||
|
||||
@ -180,10 +180,12 @@ impl CspHashes {
|
||||
if dangerous_disable_asset_csp_modification.can_modify("script-src") {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(
|
||||
&std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead {
|
||||
path: path.to_path_buf(),
|
||||
error,
|
||||
})?,
|
||||
&std::fs::read(path)
|
||||
.map(|b| tauri_utils::html::normalize_script_for_csp(&b))
|
||||
.map_err(|error| EmbeddedAssetsError::AssetRead {
|
||||
path: path.to_path_buf(),
|
||||
error,
|
||||
})?,
|
||||
);
|
||||
let hash = hasher.finalize();
|
||||
self.scripts.push(format!(
|
||||
|
||||
@ -286,6 +286,38 @@ pub fn inline_isolation(document: &NodeRef, dir: &Path) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalize line endings in script content to match what the browser uses for CSP hashing.
|
||||
///
|
||||
/// According to the HTML spec, browsers normalize:
|
||||
/// - `\r\n` → `\n`
|
||||
/// - `\r` → `\n`
|
||||
pub fn normalize_script_for_csp(input: &[u8]) -> Vec<u8> {
|
||||
let mut output = Vec::with_capacity(input.len());
|
||||
|
||||
let mut i = 0;
|
||||
while i < input.len() {
|
||||
match input[i] {
|
||||
b'\r' => {
|
||||
if i + 1 < input.len() && input[i + 1] == b'\n' {
|
||||
// CRLF → LF
|
||||
output.push(b'\n');
|
||||
i += 2;
|
||||
} else {
|
||||
// Lone CR → LF
|
||||
output.push(b'\n');
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
output.push(input[i]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@ -307,4 +339,14 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_script_for_csp() {
|
||||
let js = "// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\r// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\r\n\r\nwindow.__TAURI_ISOLATION_HOOK__ = (payload, options) => {\r\n return payload\r\n}\r\n";
|
||||
let expected = "// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\n// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\n\nwindow.__TAURI_ISOLATION_HOOK__ = (payload, options) => {\n return payload\n}\n";
|
||||
assert_eq!(
|
||||
super::normalize_script_for_csp(js.as_bytes()),
|
||||
expected.as_bytes()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user