Harden window evidence adapters

This commit is contained in:
2026-05-25 21:03:36 -04:00
parent 92cc023b4d
commit 7b1bc32c3f
2 changed files with 61 additions and 12 deletions
+36 -7
View File
@@ -27,8 +27,12 @@ pub fn get_snapshot() -> WindowSnapshot {
pub fn minimize_other(title: &str) { pub fn minimize_other(title: &str) {
let window_info = get_window_info(); let window_info = get_window_info();
if &window_info.title != title { if window_info.wid.is_empty() {
run(&format!("xdotool windowminimize {}", window_info.wid)); return;
}
if window_info.title != title {
run_xdotool(&["windowminimize", &window_info.wid]);
} }
} }
@@ -38,8 +42,12 @@ struct WindowInfo {
wid: String, wid: String,
} }
fn run(cmd: &str) -> Option<String> { fn is_valid_window_id(wid: &str) -> bool {
let output = Command::new("sh").arg("-c").arg(cmd).output(); !wid.is_empty() && wid.bytes().all(|byte| byte.is_ascii_digit())
}
fn run_xdotool(args: &[&str]) -> Option<String> {
let output = Command::new("xdotool").args(args).output();
let Ok(Output { let Ok(Output {
status, status,
@@ -68,17 +76,38 @@ fn get_window_info() -> WindowInfo {
wid: "".to_string(), wid: "".to_string(),
}; };
let Some(wid) = run("xdotool getactivewindow") else { let Some(wid) = run_xdotool(&["getactivewindow"]) else {
return none; return none;
}; };
let Some(class) = run(&format!("xdotool getwindowclassname {wid}")) else { if !is_valid_window_id(&wid) {
return none; return none;
}; };
let Some(title) = run(&format!("xdotool getwindowname {wid}")) else { let Some(class) = run_xdotool(&["getwindowclassname", &wid]) else {
return none;
};
let Some(title) = run_xdotool(&["getwindowname", &wid]) else {
return none; return none;
}; };
WindowInfo { title, class, wid } WindowInfo { title, class, wid }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_window_id_accepts_ascii_digits_only() {
assert!(is_valid_window_id("12345"));
assert!(is_valid_window_id("0"));
assert!(!is_valid_window_id(""));
assert!(!is_valid_window_id("12abc"));
assert!(!is_valid_window_id(" 123"));
assert!(!is_valid_window_id("123 "));
assert!(!is_valid_window_id("123"));
}
}
+25 -5
View File
@@ -10,19 +10,32 @@ pub fn get_title_clean() -> String {
} }
pub fn get_snapshot() -> WindowSnapshot { pub fn get_snapshot() -> WindowSnapshot {
let title = get_window_info().title; let window_info = get_window_info();
if window_info.hwnd.is_null() {
return WindowSnapshot::unavailable("foreground window unavailable");
}
let re = Regex::new(r"-?\d+([:.]\d+)+%?").unwrap(); let re = Regex::new(r"-?\d+([:.]\d+)+%?").unwrap();
let title = re.replace_all(&window_info.title, "").to_string();
let health = if window_info.title.is_empty() {
EvidenceHealth::Degraded("foreground window title unavailable".to_string())
} else {
EvidenceHealth::Degraded("window class unavailable on current Windows adapter".to_string())
};
WindowSnapshot { WindowSnapshot {
title: re.replace_all(&title, "").to_string(), title,
class: None, class: None,
health: EvidenceHealth::Degraded( health,
"window class unavailable on current Windows adapter".to_string(),
),
} }
} }
pub fn minimize_other(title: &str) { pub fn minimize_other(title: &str) {
let window_info = get_window_info(); let window_info = get_window_info();
if window_info.hwnd.is_null() {
return;
}
if window_info.title != title { if window_info.title != title {
unsafe { unsafe {
ShowWindow(window_info.hwnd, SW_MINIMIZE); ShowWindow(window_info.hwnd, SW_MINIMIZE);
@@ -38,6 +51,13 @@ struct WindowInfo {
fn get_window_info() -> WindowInfo { fn get_window_info() -> WindowInfo {
unsafe { unsafe {
let hwnd = GetForegroundWindow(); let hwnd = GetForegroundWindow();
if hwnd.is_null() {
return WindowInfo {
title: String::new(),
hwnd,
};
}
let mut text: [u16; 512] = [0; 512]; let mut text: [u16; 512] = [0; 512];
let len = GetWindowTextW(hwnd, text.as_mut_ptr(), text.len() as i32) as usize; let len = GetWindowTextW(hwnd, text.as_mut_ptr(), text.len() as i32) as usize;
let title = OsString::from_wide(&text[..len]) let title = OsString::from_wide(&text[..len])