From 5edad9b97cacb99a6513e966c3c84ef02edb06a2 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Mon, 7 Jul 2025 07:04:49 +0400 Subject: [PATCH] fix: prevent version downgrade for camoufox --- src-tauri/src/api_client.rs | 100 +++++++++++++++++++---- src-tauri/src/auto_updater.rs | 94 +++++++++++++++------ src/components/create-profile-dialog.tsx | 14 ++-- 3 files changed, 161 insertions(+), 47 deletions(-) diff --git a/src-tauri/src/api_client.rs b/src-tauri/src/api_client.rs index 27b3eb3..b7b5225 100644 --- a/src-tauri/src/api_client.rs +++ b/src-tauri/src/api_client.rs @@ -9,21 +9,21 @@ use std::time::{SystemTime, UNIX_EPOCH}; use crate::browser::GithubRelease; #[derive(Debug, Clone, PartialEq, Eq)] -struct VersionComponent { - major: u32, - minor: u32, - patch: u32, - pre_release: Option, +pub struct VersionComponent { + pub major: u32, + pub minor: u32, + pub patch: u32, + pub pre_release: Option, } #[derive(Debug, Clone, PartialEq, Eq)] -struct PreRelease { - kind: PreReleaseKind, - number: Option, +pub struct PreRelease { + pub kind: PreReleaseKind, + pub number: Option, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -enum PreReleaseKind { +pub enum PreReleaseKind { Alpha, Beta, RC, @@ -32,7 +32,7 @@ enum PreReleaseKind { } impl VersionComponent { - fn parse(version: &str) -> Self { + pub fn parse(version: &str) -> Self { let version = version.trim(); // Handle special case for Zen Browser twilight releases @@ -260,12 +260,8 @@ pub fn is_browser_version_nightly( false } "camoufox" => { - // For Camoufox, all releases are generally stable unless marked as prerelease - if let Some(name) = release_name { - name.to_lowercase().contains("alpha") - } else { - false - } + // For Camoufox, beta versions are actually the stable releases + false } _ => { // Default fallback @@ -1992,4 +1988,76 @@ mod tests { assert_eq!(versions[2], "135.0.5beta22"); assert_eq!(versions[3], "135.0.5beta21"); } + + #[test] + fn test_camoufox_user_reported_versions() { + // Test the exact versions reported by the user: 135.0.1beta24 vs 135.0beta22 + let v22 = VersionComponent::parse("135.0beta22"); + let v24 = VersionComponent::parse("135.0.1beta24"); + + println!("User reported v22: {v22:?}"); + println!("User reported v24: {v24:?}"); + + // 135.0.1beta24 should be greater than 135.0beta22 (newer patch version) + assert!( + v24 > v22, + "135.0.1beta24 should be greater than 135.0beta22, but got: v24={v24:?} vs v22={v22:?}" + ); + + // Test sorting of the exact user-reported versions + let mut versions = vec!["135.0beta22".to_string(), "135.0.1beta24".to_string()]; + + sort_versions(&mut versions); + + println!("User reported sorted versions: {versions:?}"); + + // Should be sorted from newest to oldest + assert_eq!( + versions[0], "135.0.1beta24", + "135.0.1beta24 should be first (newest)" + ); + assert_eq!( + versions[1], "135.0beta22", + "135.0beta22 should be second (older)" + ); + } + + #[test] + fn test_camoufox_version_classification() { + // Test that Camoufox beta versions are now correctly classified as stable (not nightly) + assert!( + !is_browser_version_nightly("camoufox", "135.0beta22", None), + "135.0beta22 should be classified as stable for Camoufox" + ); + assert!( + !is_browser_version_nightly("camoufox", "135.0.1beta24", None), + "135.0.1beta24 should be classified as stable for Camoufox" + ); + + // Test with release names too - beta releases should be stable + assert!( + !is_browser_version_nightly("camoufox", "135.0beta22", Some("Release Beta 22")), + "Release with 'Beta' in name should be classified as stable for Camoufox" + ); + + // Test that stable versions are not classified as nightly + assert!( + !is_browser_version_nightly("camoufox", "135.0", None), + "135.0 should be classified as stable" + ); + assert!( + !is_browser_version_nightly("camoufox", "135.0.1", None), + "135.0.1 should be classified as stable" + ); + + // Test alpha and RC versions are still considered nightly + assert!( + is_browser_version_nightly("camoufox", "136.0alpha1", None), + "136.0alpha1 should be classified as nightly/prerelease" + ); + assert!( + is_browser_version_nightly("camoufox", "136.0rc1", None), + "136.0rc1 should be classified as nightly/prerelease" + ); + } } diff --git a/src-tauri/src/auto_updater.rs b/src-tauri/src/auto_updater.rs index 3e2558a..3617ee8 100644 --- a/src-tauri/src/auto_updater.rs +++ b/src-tauri/src/auto_updater.rs @@ -407,22 +407,17 @@ impl AutoUpdater { } fn is_version_newer(&self, version1: &str, version2: &str) -> bool { - self.compare_versions(version1, version2) == std::cmp::Ordering::Greater + // Use the proper VersionComponent comparison from api_client.rs + let version_a = crate::api_client::VersionComponent::parse(version1); + let version_b = crate::api_client::VersionComponent::parse(version2); + version_a > version_b } fn compare_versions(&self, version1: &str, version2: &str) -> std::cmp::Ordering { - // Basic semantic version comparison - let v1_parts = self.parse_version(version1); - let v2_parts = self.parse_version(version2); - - v1_parts.cmp(&v2_parts) - } - - fn parse_version(&self, version: &str) -> Vec { - version - .split(&['.', 'a', 'b', '-', '_'][..]) - .filter_map(|part| part.parse::().ok()) - .collect() + // Use the proper VersionComponent comparison from api_client.rs + let version_a = crate::api_client::VersionComponent::parse(version1); + let version_b = crate::api_client::VersionComponent::parse(version2); + version_a.cmp(&version_b) } fn get_auto_update_state_file(&self) -> PathBuf { @@ -570,6 +565,68 @@ mod tests { assert!(!updater.is_version_newer("1.0.0", "1.0.0")); } + #[test] + fn test_camoufox_beta_version_comparison() { + let updater = AutoUpdater::new(); + + // Test the exact user-reported scenario: 135.0.1beta24 vs 135.0beta22 + assert!( + updater.is_version_newer("135.0.1beta24", "135.0beta22"), + "135.0.1beta24 should be newer than 135.0beta22" + ); + + assert_eq!( + updater.compare_versions("135.0.1beta24", "135.0beta22"), + std::cmp::Ordering::Greater, + "135.0.1beta24 should compare as greater than 135.0beta22" + ); + + // Test other camoufox beta version combinations + assert!( + updater.is_version_newer("135.0.5beta24", "135.0.5beta22"), + "135.0.5beta24 should be newer than 135.0.5beta22" + ); + + assert!( + updater.is_version_newer("135.0.1beta1", "135.0beta1"), + "135.0.1beta1 should be newer than 135.0beta1 due to patch version" + ); + + // Test that older versions are not considered newer + assert!( + !updater.is_version_newer("135.0beta22", "135.0.1beta24"), + "135.0beta22 should NOT be newer than 135.0.1beta24" + ); + } + + #[test] + fn test_beta_version_ordering_comprehensive() { + let updater = AutoUpdater::new(); + + // Test various beta version patterns that could appear in camoufox + let test_cases = vec![ + ("135.0.1beta24", "135.0beta22", true), // User reported case + ("135.0.5beta24", "135.0.5beta22", true), // Same patch, different beta + ("135.1beta1", "135.0beta99", true), // Higher minor beats beta number + ("136.0beta1", "135.9.9beta99", true), // Higher major beats everything + ("135.0.1beta1", "135.0beta1", true), // Patch version matters + ("135.0beta22", "135.0.1beta24", false), // Reverse of user case + ]; + + for (newer, older, should_be_newer) in test_cases { + let result = updater.is_version_newer(newer, older); + assert_eq!( + result, + should_be_newer, + "Expected {} {} {} but got {}", + newer, + if should_be_newer { ">" } else { "<=" }, + older, + if result { "true" } else { "false" } + ); + } + } + #[test] fn test_check_profile_update_stable_to_stable() { let updater = AutoUpdater::new(); @@ -854,15 +911,4 @@ mod tests { let loaded_state: AutoUpdateState = serde_json::from_str(&content).unwrap(); assert_eq!(loaded_state.pending_updates.len(), 0); } - - #[test] - fn test_parse_version() { - let updater = AutoUpdater::new(); - - assert_eq!(updater.parse_version("1.2.3"), vec![1, 2, 3]); - assert_eq!(updater.parse_version("1.2.3-alpha"), vec![1, 2, 3]); - assert_eq!(updater.parse_version("1.2.3a1"), vec![1, 2, 3, 1]); - assert_eq!(updater.parse_version("1.2.3b2"), vec![1, 2, 3, 2]); - assert_eq!(updater.parse_version("10.0.0"), vec![10, 0, 0]); - } } diff --git a/src/components/create-profile-dialog.tsx b/src/components/create-profile-dialog.tsx index 763a8fc..ee63040 100644 --- a/src/components/create-profile-dialog.tsx +++ b/src/components/create-profile-dialog.tsx @@ -327,13 +327,6 @@ export function CreateProfileDialog({
- {/* Anti-Detect Description */} -
-

- Powered by Camoufox -

-
- {/* Profile Name - Common to both tabs */}
@@ -403,6 +396,13 @@ export function CreateProfileDialog({ + {/* Anti-Detect Description */} +
+

+ Powered by Camoufox +

+
+
{/* Camoufox Download Status */} {!isBrowserVersionAvailable("camoufox") &&