diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index d3691b57558..4a795c99b00 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -73,6 +73,17 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +[[package]] +name = "apple-bundle" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a9a3a9da7ba0220d2ee5a02b6be5e0dbc73d9e9e74d8ffb5f1a7d32275e7282" +dependencies = [ + "plist", + "serde", + "serde_plain", +] + [[package]] name = "arboard" version = "3.4.1" @@ -709,6 +720,7 @@ version = "0.0.0" dependencies = [ "aes", "anyhow", + "apple-bundle", "arboard", "async-stream", "base64", @@ -737,6 +749,7 @@ dependencies = [ "scopeguard", "security-framework", "security-framework-sys", + "serde", "sha2", "ssh-encoding", "ssh-key", @@ -1950,6 +1963,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64", + "indexmap", + "quick-xml 0.32.0", + "serde", + "time", +] + [[package]] name = "png" version = "0.16.8" @@ -2033,6 +2059,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + [[package]] name = "quick-xml" version = "0.36.2" @@ -2293,24 +2328,33 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" @@ -2858,7 +2902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", - "quick-xml", + "quick-xml 0.36.2", "quote", ] diff --git a/apps/desktop/desktop_native/core/Cargo.toml b/apps/desktop/desktop_native/core/Cargo.toml index f4355d0ec40..6ff163b294e 100644 --- a/apps/desktop/desktop_native/core/Cargo.toml +++ b/apps/desktop/desktop_native/core/Cargo.toml @@ -61,7 +61,6 @@ pkcs8 = { version = "=0.10.2", features = ["alloc", "encryption", "pem"] } rsa = "=0.9.6" ed25519 = { version = "=2.2.3", features = ["pkcs8"] } sysinfo = { version = "0.32.0", features = ["windows"] } -icns = "0.3.1" [target.'cfg(windows)'.dependencies] widestring = { version = "=1.1.0", optional = true } @@ -85,6 +84,9 @@ keytar = "=0.1.6" core-foundation = { version = "=0.10.0", optional = true } security-framework = { version = "=3.0.0", optional = true } security-framework-sys = { version = "=2.12.0", optional = true } +icns = "0.3.1" +apple-bundle = "0.1.4" +serde = { version = "1.0.215", features = ["derive", "serde_derive"] } [target.'cfg(target_os = "linux")'.dependencies] gio = { version = "=0.19.5", optional = true } diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/application_info/macos.rs b/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/application_info/macos.rs index d8d898b5918..614a9a0c679 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/application_info/macos.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/application_info/macos.rs @@ -1,5 +1,7 @@ +use apple_bundle::plist; use base64::prelude::BASE64_STANDARD; use icns::{IconFamily, IconType}; +use serde::{Deserialize, Serialize}; use sysinfo::{Pid, System}; use std::{fs::File, io::{BufReader, BufWriter}, process::Command}; use base64::prelude::*; @@ -21,32 +23,37 @@ pub fn get_info(pid: usize) -> Result { if proc.is_none() { break; } - - println!("checking parent: {:?} {:?}", ppid, proc.unwrap().name()); - let parent_info = get_info_for_pid(ppid.as_u32() as usize)?; if parent_info.is_installed_app { - println!("Parent app installed, returning parent app"); return Ok(parent_info); } - if let Ok(new_ppid) = get_parent_pid(ppid) { - println!("Found parent using sysinfo"); - ppid = new_ppid; - } else { - if let Ok(new_ppid) = get_parent_fallback(ppid) { - println!("Found parent using fallback"); - ppid = new_ppid; - } else { - break; - } - } + ppid = get_parent(ppid)?; } println!("No app found, returning initial app"); Ok(app_info) } +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Default)] +pub struct InfoPlist { + #[serde( + rename = "CFBundleName", + skip_serializing_if = "Option::is_none" + )] + pub bundle_name: Option, + #[serde( + rename = "CFBundleDisplayName", + skip_serializing_if = "Option::is_none" + )] + pub bundle_display_name: Option, + #[serde( + rename = "CFBundleIconFile", + skip_serializing_if = "Option::is_none" + )] + pub bundle_icon_file: Option, +} + fn get_info_for_pid(pid: usize) -> Result { let sys = System::new_all(); // get with pid @@ -54,22 +61,30 @@ fn get_info_for_pid(pid: usize) -> Result { let executable_path = proc.unwrap().exe().ok_or(anyhow::anyhow!("Executable path not found"))?.to_str().unwrap().to_string(); let process_name = proc.ok_or(anyhow::anyhow!("Process not found"))?.name(); - println!("executable_path: {:?}", executable_path); - // if path stars with /Applications/ if executable_path.starts_with("/Applications/") { let application_name = executable_path.split("/").last().ok_or(anyhow::anyhow!("App name not found"))?; let package_name = executable_path.split("/").nth(2).ok_or(anyhow::anyhow!("Package name not found"))?; - + let info_plist_path = format!("/Applications/{}/Contents/Info.plist", package_name); + let info_plist = std::fs::read(info_plist_path).map_err(|e| anyhow::anyhow!("Error reading Info.plist: {:?}", e))?; + let info_plist: InfoPlist = plist::from_bytes(&info_plist).map_err(|e| anyhow::anyhow!("Error parsing Info.plist: {:?}", e))?; + let application_name = info_plist.bundle_display_name.unwrap_or(application_name.to_string()); + let icon_name = info_plist.bundle_icon_file.unwrap_or("AppIcon.icns".to_string()); + let icon_name = if icon_name.ends_with(".icns") { + icon_name + } else { + format!("{}.icns", icon_name) + }; + let icon = get_icon(package_name, &icon_name).ok(); return Ok(ApplicationInfo { - name: application_name.to_string(), + name: application_name, path: Some(executable_path.clone()), - icon: get_icon(package_name).ok(), + icon, is_installed_app: true, }); } else { return Ok(ApplicationInfo { - name: process_name.to_str().unwrap().to_string(), + name: process_name.to_str().unwrap_or_else(|| "unknown process").to_string(), path: None, icon: None, is_installed_app: false, @@ -77,11 +92,11 @@ fn get_info_for_pid(pid: usize) -> Result { } } -fn get_icon(package_name: &str) -> Result { - let icon_path = format!("/Applications/{}/Contents/Resources/AppIcon.icns", package_name); +fn get_icon(package_name: &str, icon_name: &str) -> Result { + let icon_path = format!("/Applications/{}/Contents/Resources/{}", package_name, icon_name); let file = BufReader::new(File::open(icon_path)?); let icon_family = IconFamily::read(file)?; - let image = icon_family.get_icon_with_type(IconType::RGBA32_128x128)?; + let image = icon_family.get_icon_with_type(IconType::RGBA32_128x128).unwrap(); let mut buffer = Vec::new(); let file = BufWriter::new(&mut buffer); image.write_png(file)?; @@ -109,4 +124,8 @@ fn get_parent_fallback(pid: Pid) -> Result { let parent_pid = output.lines().nth(1).ok_or(anyhow::anyhow!("Line not found"))?.split_whitespace().nth(0).ok_or(anyhow::anyhow!("Column not found"))?; let parent_pid = parent_pid.parse::()?; Ok(Pid::from(parent_pid)) +} + +fn get_parent(pid: Pid) -> Result { + get_parent_pid(pid).or_else(|_| get_parent_fallback(pid)) } \ No newline at end of file