Stop executing AppImages during analysis, add screenshot lightbox and favicons
- fuse.rs: Replace Command::new(appimage_path) with 256KB binary scan for runtime detection - prevents apps like Affinity from launching on tile click - fuse.rs: Read only 12 bytes for Type 2 magic check instead of entire file - security.rs: Use find_squashfs_offset_for() instead of executing AppImages with --appimage-offset flag - updater.rs: Read only first 1MB for update info instead of entire file - detail_view.rs: Click screenshots to open in lightbox dialog - detail_view.rs: Fetch favicons from Google favicon service for link rows
This commit is contained in:
@@ -171,36 +171,37 @@ pub fn determine_app_fuse_status(
|
||||
}
|
||||
|
||||
/// Check if the AppImage uses the new type2-runtime with statically linked FUSE.
|
||||
/// The new runtime embeds FUSE support and doesn't need system libfuse.
|
||||
/// Scans the first 256KB of the binary for runtime signatures instead of executing
|
||||
/// the AppImage (which can hang for apps with custom AppRun scripts like Affinity).
|
||||
fn has_static_runtime(appimage_path: &Path) -> bool {
|
||||
// The new type2-runtime responds to --appimage-version with a version string
|
||||
// containing "type2-runtime" or a recent date
|
||||
let output = Command::new(appimage_path)
|
||||
.arg("--appimage-version")
|
||||
.env("APPIMAGE_EXTRACT_AND_RUN", "1")
|
||||
.output();
|
||||
|
||||
if let Ok(output) = output {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).to_lowercase();
|
||||
let combined = format!("{}{}", stdout, stderr);
|
||||
// New runtime identifies itself
|
||||
return combined.contains("type2-runtime")
|
||||
|| combined.contains("static")
|
||||
|| combined.contains("libfuse3");
|
||||
}
|
||||
false
|
||||
use std::io::Read;
|
||||
let mut file = match std::fs::File::open(appimage_path) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return false,
|
||||
};
|
||||
// The runtime signature is in the ELF binary header area, well within first 256KB
|
||||
let mut buf = vec![0u8; 256 * 1024];
|
||||
let n = match file.read(&mut buf) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let data = &buf[..n];
|
||||
let haystack = String::from_utf8_lossy(data).to_lowercase();
|
||||
haystack.contains("type2-runtime")
|
||||
|| haystack.contains("libfuse3")
|
||||
}
|
||||
|
||||
/// Check if --appimage-extract-and-run is supported.
|
||||
fn supports_extract_and_run(appimage_path: &Path) -> bool {
|
||||
// Virtually all Type 2 AppImages support this flag
|
||||
// We check by looking at the appimage type (offset 8 in the file)
|
||||
if let Ok(data) = std::fs::read(appimage_path) {
|
||||
if data.len() > 11 {
|
||||
// Check for AppImage Type 2 magic at offset 8
|
||||
return data[8] == 0x41 && data[9] == 0x49 && data[10] == 0x02;
|
||||
}
|
||||
// Check for AppImage Type 2 magic at offset 8 - only need to read 12 bytes
|
||||
use std::io::Read;
|
||||
let mut file = match std::fs::File::open(appimage_path) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let mut header = [0u8; 12];
|
||||
if file.read_exact(&mut header).is_ok() {
|
||||
return header[8] == 0x41 && header[9] == 0x49 && header[10] == 0x02;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
@@ -155,17 +155,11 @@ fn version_from_soname(soname: &str) -> Option<String> {
|
||||
|
||||
/// Extract the list of shared libraries bundled inside an AppImage.
|
||||
pub fn inventory_bundled_libraries(appimage_path: &Path) -> Vec<BundledLibrary> {
|
||||
// Get squashfs offset
|
||||
let offset_output = Command::new(appimage_path)
|
||||
.arg("--appimage-offset")
|
||||
.env("APPIMAGE_EXTRACT_AND_RUN", "1")
|
||||
.output();
|
||||
|
||||
let offset = match offset_output {
|
||||
Ok(out) if out.status.success() => {
|
||||
String::from_utf8_lossy(&out.stdout).trim().to_string()
|
||||
}
|
||||
_ => return Vec::new(),
|
||||
// Get squashfs offset via binary scan (never execute the AppImage -
|
||||
// some apps like Affinity have custom AppRun scripts that ignore flags)
|
||||
let offset = match crate::core::inspector::find_squashfs_offset_for(appimage_path) {
|
||||
Some(o) => o.to_string(),
|
||||
None => return Vec::new(),
|
||||
};
|
||||
|
||||
// Use unsquashfs to list all files with details
|
||||
@@ -250,18 +244,9 @@ pub fn detect_version_from_binary(
|
||||
appimage_path: &Path,
|
||||
lib_file_path: &str,
|
||||
) -> Option<String> {
|
||||
// Get squashfs offset
|
||||
let offset_output = Command::new(appimage_path)
|
||||
.arg("--appimage-offset")
|
||||
.env("APPIMAGE_EXTRACT_AND_RUN", "1")
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
if !offset_output.status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let offset = String::from_utf8_lossy(&offset_output.stdout).trim().to_string();
|
||||
// Get squashfs offset via binary scan (never execute the AppImage)
|
||||
let offset = crate::core::inspector::find_squashfs_offset_for(appimage_path)?
|
||||
.to_string();
|
||||
|
||||
// Extract the specific library to a temp file
|
||||
let temp_dir = tempfile::tempdir().ok()?;
|
||||
|
||||
@@ -119,7 +119,14 @@ pub fn parse_update_info(raw: &str) -> Option<UpdateType> {
|
||||
/// named ".upd_info" or ".updinfo". It can also be found at a fixed offset
|
||||
/// in the AppImage runtime (bytes 0x414..0x614 in the ELF header area).
|
||||
pub fn read_update_info(path: &Path) -> Option<String> {
|
||||
let data = fs::read(path).ok()?;
|
||||
// Only read the first 1MB - update info is always in the ELF header area,
|
||||
// never deep in the squashfs payload. Avoids loading 1.5GB+ files into memory.
|
||||
let mut file = fs::File::open(path).ok()?;
|
||||
let file_len = file.metadata().ok()?.len() as usize;
|
||||
let read_len = file_len.min(1024 * 1024);
|
||||
let mut data = vec![0u8; read_len];
|
||||
use std::io::Read;
|
||||
file.read_exact(&mut data).ok()?;
|
||||
|
||||
// Method 1: Try to read from fixed offset range in AppImage Type 2 runtime.
|
||||
// The update info is typically at offset 0xC48 (3144) in the ELF, but the
|
||||
|
||||
Reference in New Issue
Block a user