diff --git a/src-tauri/src/profile/manager.rs b/src-tauri/src/profile/manager.rs index 0313a1b..eb0f128 100644 --- a/src-tauri/src/profile/manager.rs +++ b/src-tauri/src/profile/manager.rs @@ -281,8 +281,8 @@ impl ProfileManager { } // Find the profile by ID - let profile_uuid = uuid::Uuid::parse_str(profile_id) - .map_err(|_| format!("Invalid profile ID: {profile_id}"))?; + let profile_uuid = + uuid::Uuid::parse_str(profile_id).map_err(|_| format!("Invalid profile ID: {profile_id}"))?; let mut profile = existing_profiles .into_iter() .find(|p| p.id == profile_uuid) @@ -315,8 +315,8 @@ impl ProfileManager { println!("Attempting to delete profile with ID: {profile_id}"); // Find the profile by ID - let profile_uuid = uuid::Uuid::parse_str(profile_id) - .map_err(|_| format!("Invalid profile ID: {profile_id}"))?; + let profile_uuid = + uuid::Uuid::parse_str(profile_id).map_err(|_| format!("Invalid profile ID: {profile_id}"))?; let profiles = self.list_profiles()?; let profile = profiles .into_iter() @@ -345,7 +345,10 @@ impl ProfileManager { return Err(format!("Failed to completely delete profile '{}'", profile.name).into()); } - println!("Profile '{}' (ID: {}) deleted successfully", profile.name, profile_id); + println!( + "Profile '{}' (ID: {}) deleted successfully", + profile.name, profile_id + ); // Rebuild tag suggestions after deletion let _ = crate::tag_manager::TAG_MANAGER.lock().map(|tm| { @@ -367,8 +370,8 @@ impl ProfileManager { version: &str, ) -> Result> { // Find the profile by ID - let profile_uuid = uuid::Uuid::parse_str(profile_id) - .map_err(|_| format!("Invalid profile ID: {profile_id}"))?; + let profile_uuid = + uuid::Uuid::parse_str(profile_id).map_err(|_| format!("Invalid profile ID: {profile_id}"))?; let profiles = self.list_profiles()?; let mut profile = profiles .into_iter() @@ -462,8 +465,8 @@ impl ProfileManager { tags: Vec, ) -> Result> { // Find the profile by ID - let profile_uuid = uuid::Uuid::parse_str(profile_id) - .map_err(|_| format!("Invalid profile ID: {profile_id}"))?; + let profile_uuid = + uuid::Uuid::parse_str(profile_id).map_err(|_| format!("Invalid profile ID: {profile_id}"))?; let profiles = self.list_profiles()?; let mut profile = profiles .into_iter() @@ -514,7 +517,8 @@ impl ProfileManager { if profile.process_id.is_some() { return Err( format!( - "Cannot delete profile '{}' while browser is running. Please stop the browser first.", profile.name + "Cannot delete profile '{}' while browser is running. Please stop the browser first.", + profile.name ) .into(), ); @@ -544,10 +548,11 @@ impl ProfileManager { config: CamoufoxConfig, ) -> Result<(), Box> { // Find the profile by ID - let profile_uuid = uuid::Uuid::parse_str(profile_id) - .map_err(|_| -> Box { + let profile_uuid = uuid::Uuid::parse_str(profile_id).map_err( + |_| -> Box { format!("Invalid profile ID: {profile_id}").into() - })?; + }, + )?; let profiles = self .list_profiles() @@ -582,7 +587,10 @@ impl ProfileManager { format!("Failed to save profile: {e}").into() })?; - println!("Camoufox configuration updated for profile '{}' (ID: {}).", profile.name, profile_id); + println!( + "Camoufox configuration updated for profile '{}' (ID: {}).", + profile.name, profile_id + ); // Emit profile config update event if let Err(e) = app_handle.emit("profiles-changed", ()) { @@ -599,10 +607,11 @@ impl ProfileManager { proxy_id: Option, ) -> Result> { // Find the profile by ID - let profile_uuid = uuid::Uuid::parse_str(profile_id) - .map_err(|_| -> Box { + let profile_uuid = uuid::Uuid::parse_str(profile_id).map_err( + |_| -> Box { format!("Invalid profile ID: {profile_id}").into() - })?; + }, + )?; let profiles = self .list_profiles() diff --git a/src-tauri/src/settings_manager.rs b/src-tauri/src/settings_manager.rs index 31af4eb..d012e29 100644 --- a/src-tauri/src/settings_manager.rs +++ b/src-tauri/src/settings_manager.rs @@ -8,9 +8,9 @@ use crate::version_updater; use aes_gcm::{ aead::{Aead, AeadCore, KeyInit, OsRng}, - Aes256Gcm, Key, Nonce + Aes256Gcm, Key, Nonce, }; -use argon2::{Argon2, PasswordHasher, password_hash::SaltString}; +use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct TableSortingSettings { @@ -213,41 +213,43 @@ impl SettingsManager { } let vault_password = Self::get_vault_password(); - + // Generate a random salt for Argon2 let salt = SaltString::generate(&mut OsRng); - + // Use Argon2 to derive a 32-byte key from the vault password let argon2 = Argon2::default(); - let password_hash = argon2.hash_password(vault_password.as_bytes(), &salt) - .map_err(|e| format!("Argon2 key derivation failed: {}", e))?; + let password_hash = argon2 + .hash_password(vault_password.as_bytes(), &salt) + .map_err(|e| format!("Argon2 key derivation failed: {e}"))?; let hash_value = password_hash.hash.unwrap(); let hash_bytes = hash_value.as_bytes(); - + // Take first 32 bytes for AES-256 key let key = Key::::from_slice(&hash_bytes[..32]); let cipher = Aes256Gcm::new(key); - + // Generate a random nonce let nonce = Aes256Gcm::generate_nonce(&mut OsRng); - + // Encrypt the token - let ciphertext = cipher.encrypt(&nonce, token.as_bytes()) - .map_err(|e| format!("Encryption failed: {}", e))?; - + let ciphertext = cipher + .encrypt(&nonce, token.as_bytes()) + .map_err(|e| format!("Encryption failed: {e}"))?; + // Create file data with header, salt, nonce, and encrypted data let mut file_data = Vec::new(); file_data.extend_from_slice(b"DBAPI"); // 5-byte header file_data.push(2u8); // Version 2 (Argon2 + AES-GCM) - + // Store salt length and salt let salt_str = salt.as_str(); file_data.push(salt_str.len() as u8); file_data.extend_from_slice(salt_str.as_bytes()); - + // Store nonce (12 bytes for AES-GCM) file_data.extend_from_slice(&nonce); - + // Store ciphertext length and ciphertext file_data.extend_from_slice(&(ciphertext.len() as u32).to_le_bytes()); file_data.extend_from_slice(&ciphertext); @@ -274,22 +276,22 @@ impl SettingsManager { } let version = file_data[5]; - + // Only support Argon2 + AES-GCM (version 2) if version != 2 { return Ok(None); } - + // Argon2 + AES-GCM decryption let mut offset = 6; - + // Read salt if offset >= file_data.len() { return Ok(None); } let salt_len = file_data[offset] as usize; offset += 1; - + if offset + salt_len > file_data.len() { return Ok(None); } @@ -297,7 +299,7 @@ impl SettingsManager { let salt_str = std::str::from_utf8(salt_bytes).map_err(|_| "Invalid salt encoding")?; let salt = SaltString::from_b64(salt_str).map_err(|_| "Invalid salt format")?; offset += salt_len; - + // Read nonce (12 bytes) if offset + 12 > file_data.len() { return Ok(None); @@ -305,36 +307,41 @@ impl SettingsManager { let nonce_bytes = &file_data[offset..offset + 12]; let nonce = Nonce::from_slice(nonce_bytes); offset += 12; - + // Read ciphertext if offset + 4 > file_data.len() { return Ok(None); } let ciphertext_len = u32::from_le_bytes([ - file_data[offset], file_data[offset + 1], file_data[offset + 2], file_data[offset + 3] + file_data[offset], + file_data[offset + 1], + file_data[offset + 2], + file_data[offset + 3], ]) as usize; offset += 4; - + if offset + ciphertext_len > file_data.len() { return Ok(None); } let ciphertext = &file_data[offset..offset + ciphertext_len]; - + // Derive key using Argon2 let vault_password = Self::get_vault_password(); let argon2 = Argon2::default(); - let password_hash = argon2.hash_password(vault_password.as_bytes(), &salt) - .map_err(|e| format!("Argon2 key derivation failed: {}", e))?; + let password_hash = argon2 + .hash_password(vault_password.as_bytes(), &salt) + .map_err(|e| format!("Argon2 key derivation failed: {e}"))?; let hash_value = password_hash.hash.unwrap(); let hash_bytes = hash_value.as_bytes(); - + let key = Key::::from_slice(&hash_bytes[..32]); let cipher = Aes256Gcm::new(key); - + // Decrypt the token - let plaintext = cipher.decrypt(nonce, ciphertext) + let plaintext = cipher + .decrypt(nonce, ciphertext) .map_err(|_| "Decryption failed")?; - + match String::from_utf8(plaintext) { Ok(token) => Ok(Some(token)), Err(_) => Ok(None),