Validate chromium browser binary before installing desktop entry
This commit is contained in:
49
src/main.rs
49
src/main.rs
@@ -405,10 +405,37 @@ fn find_binary_in_path(name: &str) -> Option<PathBuf> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chromium_binary_works(path: &Path) -> Result<()> {
|
||||||
|
let output = Command::new(path)
|
||||||
|
.arg("--version")
|
||||||
|
.output()
|
||||||
|
.with_context(|| format!("Failed to execute browser binary {}", path.display()))?;
|
||||||
|
if output.status.success() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
|
let details = if !stderr.is_empty() {
|
||||||
|
stderr
|
||||||
|
} else if !stdout.is_empty() {
|
||||||
|
stdout
|
||||||
|
} else {
|
||||||
|
format!("exit code {}", output.status)
|
||||||
|
};
|
||||||
|
Err(anyhow!(
|
||||||
|
"Browser binary exists but failed to run: {} ({})",
|
||||||
|
path.display(),
|
||||||
|
details
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_chromium_binary(explicit: Option<&str>) -> Result<PathBuf> {
|
fn resolve_chromium_binary(explicit: Option<&str>) -> Result<PathBuf> {
|
||||||
if let Some(path) = explicit {
|
if let Some(path) = explicit {
|
||||||
let candidate = PathBuf::from(path);
|
let candidate = PathBuf::from(path);
|
||||||
if candidate.is_file() {
|
if candidate.is_file() {
|
||||||
|
chromium_binary_works(&candidate).with_context(|| {
|
||||||
|
"The specified browser binary does not appear to be usable. If it's a wrapper script, ensure the underlying browser exists."
|
||||||
|
})?;
|
||||||
return Ok(candidate);
|
return Ok(candidate);
|
||||||
}
|
}
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
@@ -418,7 +445,9 @@ fn resolve_chromium_binary(explicit: Option<&str>) -> Result<PathBuf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for candidate in chromium_candidates() {
|
for candidate in chromium_candidates() {
|
||||||
if let Some(path) = find_binary_in_path(candidate) {
|
if let Some(path) = find_binary_in_path(candidate)
|
||||||
|
&& chromium_binary_works(&path).is_ok()
|
||||||
|
{
|
||||||
return Ok(path);
|
return Ok(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1444,6 +1473,8 @@ mod tests {
|
|||||||
is_deskify_desktop_entry, sanitize_app_id, validate_remove_id,
|
is_deskify_desktop_entry, sanitize_app_id, validate_remove_id,
|
||||||
};
|
};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::{fs, os::unix::fs::PermissionsExt};
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sanitize_app_id_replaces_spaces_and_strips_symbols() {
|
fn sanitize_app_id_replaces_spaces_and_strips_symbols() {
|
||||||
@@ -1540,4 +1571,20 @@ mod tests {
|
|||||||
let scope: ProfileScope = serde_json::from_str("\"default\"").unwrap();
|
let scope: ProfileScope = serde_json::from_str("\"default\"").unwrap();
|
||||||
assert_eq!(scope, ProfileScope::Isolated);
|
assert_eq!(scope, ProfileScope::Isolated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resolve_chromium_binary_rejects_broken_explicit_path() {
|
||||||
|
let dir = tempdir().unwrap();
|
||||||
|
let script = dir.path().join("broken-browser");
|
||||||
|
fs::write(&script, "#!/bin/sh\nexit 1\n").unwrap();
|
||||||
|
let mut perms = fs::metadata(&script).unwrap().permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
fs::set_permissions(&script, perms).unwrap();
|
||||||
|
|
||||||
|
let err = super::resolve_chromium_binary(Some(script.to_str().unwrap()))
|
||||||
|
.err()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
assert!(err.contains("failed to run") || err.contains("does not appear to be usable"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user