From 5cc816ecc51ecdde40f545ca1eed0993893194cc Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Sun, 21 Dec 2025 13:51:58 +0400 Subject: [PATCH] fix: download correct camoufox version on macos x64 --- src-tauri/src/api_client.rs | 6 +- src-tauri/src/browser.rs | 109 ++++++++++++++++++++++++++++++++++-- src-tauri/src/downloader.rs | 26 +++++++-- 3 files changed, 129 insertions(+), 12 deletions(-) diff --git a/src-tauri/src/api_client.rs b/src-tauri/src/api_client.rs index 0345e18..04acb38 100644 --- a/src-tauri/src/api_client.rs +++ b/src-tauri/src/api_client.rs @@ -836,11 +836,11 @@ impl ApiClient { }; // Look for assets matching the pattern: camoufox-{version}-{release}-{os}.{arch}.zip + // Use ends_with for precise matching to avoid false positives + let pattern = format!(".{os_name}.{arch_name}.zip"); assets.iter().any(|asset| { let name = asset.name.to_lowercase(); - name.starts_with("camoufox-") - && name.contains(&format!("-{os_name}.{arch_name}.zip")) - && name.ends_with(".zip") + name.starts_with("camoufox-") && name.ends_with(&pattern) }) } diff --git a/src-tauri/src/browser.rs b/src-tauri/src/browser.rs index 506154e..c9c6e44 100644 --- a/src-tauri/src/browser.rs +++ b/src-tauri/src/browser.rs @@ -79,10 +79,10 @@ mod macos { executable_dir.push("Contents"); executable_dir.push("MacOS"); - // Find the first executable in the MacOS directory - let executable_path = std::fs::read_dir(&executable_dir)? + // Find executables matching the browser name pattern + let candidates: Vec<_> = std::fs::read_dir(&executable_dir)? .filter_map(Result::ok) - .find(|entry| { + .filter(|entry| { let binding = entry.file_name(); let name = binding.to_string_lossy(); name.starts_with("firefox") @@ -91,7 +91,108 @@ mod macos { || name.contains("Browser") }) .map(|entry| entry.path()) - .ok_or("No executable found in MacOS directory")?; + .collect(); + + if candidates.is_empty() { + return Err("No executable found in MacOS directory".into()); + } + + // For Camoufox, validate architecture compatibility + let executable_path = if candidates.iter().any(|p| { + p.file_name() + .and_then(|n| n.to_str()) + .map(|n| n.starts_with("camoufox")) + .unwrap_or(false) + }) { + // Find the executable that matches the current architecture + let current_arch = if cfg!(target_arch = "x86_64") { + "x86_64" + } else if cfg!(target_arch = "aarch64") { + "arm64" + } else { + return Err("Unsupported architecture".into()); + }; + + // Try to find an executable that matches the current architecture + // Use file command to check architecture + let mut found_executable = None; + let mut file_command_available = true; + + for candidate in &candidates { + match std::process::Command::new("file").arg(candidate).output() { + Ok(output) => { + if output.status.success() { + if let Ok(output_str) = String::from_utf8(output.stdout) { + let is_compatible = if current_arch == "x86_64" { + output_str.contains("x86_64") || output_str.contains("i386") + } else { + output_str.contains("arm64") || output_str.contains("aarch64") + }; + + if is_compatible { + found_executable = Some(candidate.clone()); + log::info!( + "Found compatible Camoufox executable for {}: {}", + current_arch, + candidate.display() + ); + break; + } else { + log::warn!( + "Skipping incompatible Camoufox executable: {} (architecture: {})", + candidate.display(), + output_str.trim() + ); + } + } + } else { + log::warn!( + "Failed to check architecture for {}: file command returned non-zero exit code", + candidate.display() + ); + } + } + Err(e) => { + log::warn!( + "Failed to check architecture for {} using file command: {}", + candidate.display(), + e + ); + file_command_available = false; + // Continue checking other candidates + } + } + } + + // If no compatible executable found but we have candidates, use the first one + // (fallback for cases where file command isn't available or failed) + if found_executable.is_none() && !candidates.is_empty() { + if !file_command_available { + log::warn!( + "file command not available, using first candidate: {}", + candidates[0].display() + ); + } else { + log::warn!( + "No compatible executable found for architecture {}, using first candidate: {}", + current_arch, + candidates[0].display() + ); + } + found_executable = Some(candidates[0].clone()); + } + + found_executable.ok_or_else(|| { + format!( + "No compatible Camoufox executable found for architecture {}. Available executables: {:?}", + current_arch, + candidates + ) + })? + } else { + // For other browsers, use the first matching executable + candidates[0].clone() + }; Ok(executable_path) } diff --git a/src-tauri/src/downloader.rs b/src-tauri/src/downloader.rs index d139c43..7418036 100644 --- a/src-tauri/src/downloader.rs +++ b/src-tauri/src/downloader.rs @@ -321,15 +321,31 @@ impl Downloader { _ => return None, }; - // Look for assets matching the pattern + // Use ends_with for precise matching to avoid false positives + let pattern = format!(".{os_name}.{arch_name}.zip"); let asset = assets.iter().find(|asset| { let name = asset.name.to_lowercase(); - name.starts_with("camoufox-") - && name.contains(&format!("-{os_name}.{arch_name}.zip")) - && name.ends_with(".zip") + name.starts_with("camoufox-") && name.ends_with(&pattern) }); - asset.map(|a| a.browser_download_url.clone()) + if let Some(asset) = asset { + log::info!( + "Selected Camoufox asset for {}/{}: {}", + os, + arch, + asset.name + ); + Some(asset.browser_download_url.clone()) + } else { + log::warn!( + "No matching Camoufox asset found for {}/{} with pattern '{}'. Available assets: {:?}", + os, + arch, + pattern, + assets.iter().map(|a| &a.name).collect::>() + ); + None + } } pub async fn download_browser(