| use crate::utils::protobuf; |
| use rusqlite::Connection; |
| use std::path::PathBuf; |
|
|
| fn get_antigravity_path() -> Option<PathBuf> { |
| if let Ok(config) = crate::modules::config::load_app_config() { |
| if let Some(path_str) = config.antigravity_executable { |
| let path = PathBuf::from(path_str); |
| if path.exists() { |
| return Some(path); |
| } |
| } |
| } |
| crate::modules::process::get_antigravity_executable_path() |
| } |
|
|
| |
| pub fn get_db_path() -> Result<PathBuf, String> { |
| |
| if let Some(user_data_dir) = crate::modules::process::get_user_data_dir_from_process() { |
| let custom_db_path = user_data_dir.join("User").join("globalStorage").join("state.vscdb"); |
| if custom_db_path.exists() { |
| return Ok(custom_db_path); |
| } |
| } |
|
|
| |
| if let Some(antigravity_path) = get_antigravity_path() { |
| if let Some(parent_dir) = antigravity_path.parent() { |
| let portable_db_path = PathBuf::from(parent_dir) |
| .join("data") |
| .join("user-data") |
| .join("User") |
| .join("globalStorage") |
| .join("state.vscdb"); |
|
|
| if portable_db_path.exists() { |
| return Ok(portable_db_path); |
| } |
| } |
| } |
|
|
| |
| #[cfg(target_os = "macos")] |
| { |
| let home = dirs::home_dir().ok_or("Failed to get home directory")?; |
| Ok(home.join("Library/Application Support/Antigravity/User/globalStorage/state.vscdb")) |
| } |
|
|
| #[cfg(target_os = "windows")] |
| { |
| let appdata = |
| std::env::var("APPDATA").map_err(|_| "Failed to get APPDATA environment variable".to_string())?; |
| Ok(PathBuf::from(appdata).join("Antigravity\\User\\globalStorage\\state.vscdb")) |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| let home = dirs::home_dir().ok_or("Failed to get home directory")?; |
| Ok(home.join(".config/Antigravity/User/globalStorage/state.vscdb")) |
| } |
| } |
|
|
| |
| pub fn inject_token( |
| db_path: &PathBuf, |
| access_token: &str, |
| refresh_token: &str, |
| expiry: i64, |
| email: &str, |
| is_gcp_tos: bool, |
| project_id: Option<&str>, |
| ) -> Result<String, String> { |
| crate::modules::logger::log_info("Starting Token injection..."); |
| |
| |
| let version_result = crate::modules::version::get_antigravity_version(); |
| |
| match version_result { |
| Ok(ver) => { |
| crate::modules::logger::log_info(&format!( |
| "Detected Antigravity version: {}", |
| ver.short_version |
| )); |
| |
| |
| if crate::modules::version::is_new_version(&ver) { |
| |
| crate::modules::logger::log_info( |
| "Using new format injection (antigravityUnifiedStateSync.oauthToken)", |
| ); |
| inject_new_format( |
| db_path, |
| access_token, |
| refresh_token, |
| expiry, |
| email, |
| is_gcp_tos, |
| project_id, |
| ) |
| } else { |
| |
| crate::modules::logger::log_info( |
| "Using old format injection (jetskiStateSync.agentManagerInitState)", |
| ); |
| inject_old_format(db_path, access_token, refresh_token, expiry, email) |
| } |
| } |
| Err(e) => { |
| |
| crate::modules::logger::log_warn(&format!( |
| "Version detection failed, trying both formats for compatibility: {}", |
| e |
| )); |
| |
| |
| let new_result = inject_new_format( |
| db_path, |
| access_token, |
| refresh_token, |
| expiry, |
| email, |
| is_gcp_tos, |
| project_id, |
| ); |
| |
| |
| let old_result = inject_old_format(db_path, access_token, refresh_token, expiry, email); |
| |
| |
| if new_result.is_ok() || old_result.is_ok() { |
| Ok("Token injection successful (dual format fallback)".to_string()) |
| } else { |
| Err(format!( |
| "Both formats failed - New: {:?}, Old: {:?}", |
| new_result.err(), |
| old_result.err() |
| )) |
| } |
| } |
| } |
| } |
|
|
| |
| fn inject_new_format( |
| db_path: &PathBuf, |
| access_token: &str, |
| refresh_token: &str, |
| expiry: i64, |
| email: &str, |
| is_gcp_tos: bool, |
| project_id: Option<&str>, |
| ) -> Result<String, String> { |
| let conn = Connection::open(db_path).map_err(|e| format!("Failed to open database: {}", e))?; |
| |
| |
| let oauth_info = protobuf::create_oauth_info(access_token, refresh_token, expiry, is_gcp_tos); |
| let outer_b64 = protobuf::create_unified_state_entry("oauthTokenInfoSentinelKey", &oauth_info); |
| |
| conn.execute( |
| "INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)", |
| ["antigravityUnifiedStateSync.oauthToken", &outer_b64], |
| ) |
| .map_err(|e| format!("Failed to write new format: {}", e))?; |
| |
| inject_user_status(&conn, email)?; |
|
|
| if let Some(project_id) = project_id.map(str::trim).filter(|pid| !pid.is_empty()) { |
| inject_enterprise_project_preference(&conn, project_id)?; |
| } else { |
| clear_enterprise_project_preference(&conn)?; |
| } |
|
|
| |
| conn.execute( |
| "INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)", |
| ["antigravityOnboarding", "true"], |
| ) |
| .map_err(|e| format!("Failed to write onboarding flag: {}", e))?; |
| |
| Ok("Token injection successful (new format)".to_string()) |
| } |
|
|
| fn inject_user_status(conn: &Connection, email: &str) -> Result<(), String> { |
| let payload = protobuf::create_minimal_user_status_payload(email); |
| let entry_b64 = protobuf::create_unified_state_entry("userStatusSentinelKey", &payload); |
|
|
| conn.execute( |
| "INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)", |
| ["antigravityUnifiedStateSync.userStatus", &entry_b64], |
| ) |
| .map_err(|e| format!("Failed to write user status: {}", e))?; |
|
|
| Ok(()) |
| } |
|
|
| fn inject_enterprise_project_preference(conn: &Connection, project_id: &str) -> Result<(), String> { |
| let payload = protobuf::create_string_value_payload(project_id); |
| let entry_b64 = protobuf::create_unified_state_entry("enterpriseGcpProjectId", &payload); |
|
|
| conn.execute( |
| "INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)", |
| [ |
| "antigravityUnifiedStateSync.enterprisePreferences", |
| &entry_b64, |
| ], |
| ) |
| .map_err(|e| format!("Failed to write enterprise preferences: {}", e))?; |
|
|
| Ok(()) |
| } |
|
|
| fn clear_enterprise_project_preference(conn: &Connection) -> Result<(), String> { |
| conn.execute( |
| "DELETE FROM ItemTable WHERE key = ?", |
| ["antigravityUnifiedStateSync.enterprisePreferences"], |
| ) |
| .map_err(|e| format!("Failed to clear enterprise preferences: {}", e))?; |
|
|
| Ok(()) |
| } |
|
|
| |
| fn inject_old_format( |
| db_path: &PathBuf, |
| access_token: &str, |
| refresh_token: &str, |
| expiry: i64, |
| email: &str, |
| ) -> Result<String, String> { |
| use base64::{engine::general_purpose, Engine as _}; |
| use rusqlite::Error as SqliteError; |
| |
| let conn = Connection::open(db_path) |
| .map_err(|e| format!("Failed to open database: {}", e))?; |
| |
| |
| let current_data: String = conn |
| .query_row( |
| "SELECT value FROM ItemTable WHERE key = ?", |
| ["jetskiStateSync.agentManagerInitState"], |
| |row| row.get(0), |
| ) |
| .map_err(|e| match e { |
| SqliteError::QueryReturnedNoRows => { |
| "Old format key does not exist, possibly new version Antigravity".to_string() |
| } |
| _ => format!("Failed to read data: {}", e), |
| })?; |
| |
| |
| let blob = general_purpose::STANDARD |
| .decode(¤t_data) |
| .map_err(|e| format!("Base64 decoding failed: {}", e))?; |
| |
| |
| let mut clean_data = protobuf::remove_field(&blob, 1)?; |
| clean_data = protobuf::remove_field(&clean_data, 2)?; |
| clean_data = protobuf::remove_field(&clean_data, 6)?; |
| |
| |
| let new_email_field = protobuf::create_email_field(email); |
| let new_oauth_field = protobuf::create_oauth_field(access_token, refresh_token, expiry); |
| |
| |
| |
| |
| let final_data = [clean_data, new_email_field, new_oauth_field].concat(); |
| let final_b64 = general_purpose::STANDARD.encode(&final_data); |
| |
| |
| conn.execute( |
| "UPDATE ItemTable SET value = ? WHERE key = ?", |
| [&final_b64, "jetskiStateSync.agentManagerInitState"], |
| ) |
| .map_err(|e| format!("Failed to write data: {}", e))?; |
| |
| |
| conn.execute( |
| "INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)", |
| ["antigravityOnboarding", "true"], |
| ) |
| .map_err(|e| format!("Failed to write onboarding flag: {}", e))?; |
| |
| Ok("Token injection successful (old format)".to_string()) |
| } |
|
|
| |
| pub fn write_service_machine_id(db_path: &std::path::Path, service_machine_id: &str) -> Result<(), String> { |
| let conn = Connection::open(db_path).map_err(|e| format!("Failed to open database: {}", e))?; |
| |
| conn.execute( |
| "INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)", |
| ["telemetry.serviceMachineId", service_machine_id], |
| ) |
| .map_err(|e| format!("Failed to write serviceMachineId: {}", e))?; |
|
|
| crate::modules::logger::log_info(&format!( |
| "Successfully injected serviceMachineId: {}", |
| service_machine_id |
| )); |
| |
| Ok(()) |
| } |
|
|