Fix macos appinfo

This commit is contained in:
Bernd Schoolmann 2024-11-28 16:53:13 +01:00
parent e3315c9372
commit 7d32a732b0
No known key found for this signature in database
3 changed files with 95 additions and 30 deletions

View File

@ -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",
]

View File

@ -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 }

View File

@ -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<ApplicationInfo, anyhow::Error> {
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<String>,
#[serde(
rename = "CFBundleDisplayName",
skip_serializing_if = "Option::is_none"
)]
pub bundle_display_name: Option<String>,
#[serde(
rename = "CFBundleIconFile",
skip_serializing_if = "Option::is_none"
)]
pub bundle_icon_file: Option<String>,
}
fn get_info_for_pid(pid: usize) -> Result<ApplicationInfo, anyhow::Error> {
let sys = System::new_all();
// get with pid
@ -54,22 +61,30 @@ fn get_info_for_pid(pid: usize) -> Result<ApplicationInfo, anyhow::Error> {
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<ApplicationInfo, anyhow::Error> {
}
}
fn get_icon(package_name: &str) -> Result<String, anyhow::Error> {
let icon_path = format!("/Applications/{}/Contents/Resources/AppIcon.icns", package_name);
fn get_icon(package_name: &str, icon_name: &str) -> Result<String, anyhow::Error> {
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<Pid, anyhow::Error> {
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::<usize>()?;
Ok(Pid::from(parent_pid))
}
fn get_parent(pid: Pid) -> Result<Pid, anyhow::Error> {
get_parent_pid(pid).or_else(|_| get_parent_fallback(pid))
}