dscode_extension_host/
binary_verifier.rs1use sha2::{Sha256, Digest};
8use std::fs;
9use std::path::Path;
10use tracing::warn;
11
12const ALLOWED_HASHES: &[&str] = &[
15 ];
19
20pub fn verify_binary(binary_path: &Path) -> Result<(), String> {
25 if std::env::var("DSCODE_SKIP_NODE_VERIFY").is_ok() {
27 warn!("Node.js binary verification skipped (DSCODE_SKIP_NODE_VERIFY set)");
28 return Ok(());
29 }
30
31 if ALLOWED_HASHES.is_empty() {
33 return Ok(());
34 }
35
36 let hash = compute_file_hash(binary_path)?;
37
38 if ALLOWED_HASHES.contains(&hash.as_str()) {
39 Ok(())
40 } else {
41 Err(format!(
42 "Node.js binary hash mismatch: {} (expected one of: {:?})",
43 hash, ALLOWED_HASHES
44 ))
45 }
46}
47
48fn compute_file_hash(path: &Path) -> Result<String, String> {
50 let data = fs::read(path)
51 .map_err(|e| format!("Failed to read binary {:?}: {}", path, e))?;
52
53 let mut hasher = Sha256::new();
54 hasher.update(&data);
55 let result = hasher.finalize();
56
57 Ok(format!("{:x}", result))
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use std::io::Write;
64
65 #[test]
66 fn test_compute_file_hash() {
67 let dir = tempfile::tempdir().unwrap();
68 let file_path = dir.path().join("test_binary");
69 let mut file = fs::File::create(&file_path).unwrap();
70 file.write_all(b"test content").unwrap();
71 drop(file);
72
73 let hash = compute_file_hash(&file_path).unwrap();
74 assert_eq!(hash.len(), 64); assert!(!hash.is_empty());
77 }
78
79 #[test]
80 fn test_verify_binary_skips_with_env() {
81 std::env::set_var("DSCODE_SKIP_NODE_VERIFY", "1");
83 let result = verify_binary(Path::new("/nonexistent"));
84 std::env::remove_var("DSCODE_SKIP_NODE_VERIFY");
85 assert!(result.is_ok());
86 }
87
88 #[test]
89 fn test_verify_binary_skips_empty_hashes() {
90 let result = verify_binary(Path::new("/nonexistent"));
92 assert!(result.is_ok());
93 }
94}