Fix 29 audit findings across all severity tiers
Critical: fix unsquashfs arg order, quote Exec paths with spaces, fix compare_versions antisymmetry, chunk-based signature detection, bounded ELF header reads. High: handle NULL CVE severity, prevent pipe deadlock in inspector, fix glob_match edge case, fix backup archive path collisions, async crash detection with stderr capture. Medium: gate scan on auto-scan setting, fix window size persistence, fix announce() for Stack containers, claim lightbox gesture, use serde_json for CLI output, remove dead CSS @media blocks, add detail-tab persistence, remove invalid metainfo categories, byte-level fuse signature search. Low: tighten Wayland env var detection, ELF magic validation, timeout for update info extraction, quoted arg parsing, stop watcher timer on window destroy, GSettings choices/range constraints, remove unused CSS classes, define status-ok/status-attention CSS.
This commit is contained in:
@@ -48,6 +48,20 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
view_stack.add_titled(&storage_page, Some("storage"), "Storage");
|
||||
view_stack.page(&storage_page).set_icon_name(Some("drive-harddisk-symbolic"));
|
||||
|
||||
// Restore last-used tab from GSettings
|
||||
let settings = gio::Settings::new(crate::config::APP_ID);
|
||||
let saved_tab = settings.string("detail-tab");
|
||||
if view_stack.child_by_name(&saved_tab).is_some() {
|
||||
view_stack.set_visible_child_name(&saved_tab);
|
||||
}
|
||||
|
||||
// Persist tab choice on switch
|
||||
view_stack.connect_visible_child_name_notify(move |stack| {
|
||||
if let Some(name) = stack.visible_child_name() {
|
||||
settings.set_string("detail-tab", &name).ok();
|
||||
}
|
||||
});
|
||||
|
||||
// Banner scrolls with content (not sticky) so tall banners don't eat space
|
||||
let scroll_content = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
@@ -83,6 +97,7 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
let record_id = record.id;
|
||||
let path = record.path.clone();
|
||||
let app_name_launch = record.app_name.clone().unwrap_or_else(|| record.filename.clone());
|
||||
let launch_args_raw = record.launch_args.clone();
|
||||
let db_launch = db.clone();
|
||||
let toast_launch = toast_overlay.clone();
|
||||
launch_button.connect_clicked(move |btn| {
|
||||
@@ -92,6 +107,7 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
let app_name = app_name_launch.clone();
|
||||
let db_launch = db_launch.clone();
|
||||
let toast_ref = toast_launch.clone();
|
||||
let launch_args = launcher::parse_launch_args(launch_args_raw.as_deref());
|
||||
glib::spawn_future_local(async move {
|
||||
let path_bg = path.clone();
|
||||
let result = gio::spawn_blocking(move || {
|
||||
@@ -101,7 +117,7 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
record_id,
|
||||
appimage_path,
|
||||
"gui_detail",
|
||||
&[],
|
||||
&launch_args,
|
||||
&[],
|
||||
)
|
||||
}).await;
|
||||
@@ -121,13 +137,16 @@ pub fn build_detail_page(record: &AppImageRecord, db: &Rc<Database>) -> adw::Nav
|
||||
}).await;
|
||||
if let Ok(Ok(analysis)) = analysis_result {
|
||||
let status_str = analysis.as_status_str();
|
||||
log::info!("Runtime Wayland: {} -> {}", path_clone, analysis.status_label());
|
||||
log::info!(
|
||||
"Runtime Wayland: {} -> {} (pid={}, env: {:?})",
|
||||
path_clone, analysis.status_label(), analysis.pid, analysis.env_vars,
|
||||
);
|
||||
db_wayland.update_runtime_wayland_status(record_id, status_str).ok();
|
||||
}
|
||||
});
|
||||
}
|
||||
Ok(launcher::LaunchResult::Crashed { exit_code, stderr, .. }) => {
|
||||
log::error!("App crashed on launch (exit {}): {}", exit_code.unwrap_or(-1), stderr);
|
||||
Ok(launcher::LaunchResult::Crashed { exit_code, stderr, method }) => {
|
||||
log::error!("App crashed on launch (exit {}, method: {}): {}", exit_code.unwrap_or(-1), method.as_str(), stderr);
|
||||
widgets::show_crash_dialog(&btn_ref, &app_name, exit_code, &stderr);
|
||||
}
|
||||
Ok(launcher::LaunchResult::Failed(msg)) => {
|
||||
@@ -247,9 +266,7 @@ fn build_banner(record: &AppImageRecord) -> gtk::Box {
|
||||
.margin_top(4)
|
||||
.build();
|
||||
|
||||
if record.integrated {
|
||||
badge_box.append(&widgets::status_badge("Integrated", "success"));
|
||||
}
|
||||
badge_box.append(&widgets::integration_badge(record.integrated));
|
||||
|
||||
if let Some(ref ws) = record.wayland_status {
|
||||
let status = WaylandStatus::from_str(ws);
|
||||
@@ -1582,6 +1599,10 @@ fn build_backup_group(record_id: i64, toast_overlay: &adw::ToastOverlay) -> adw:
|
||||
group.add(&empty_row);
|
||||
} else {
|
||||
for b in &backups {
|
||||
log::debug!(
|
||||
"Listing backup id={} for appimage_id={} at {}",
|
||||
b.id, b.appimage_id, b.archive_path,
|
||||
);
|
||||
let expander = adw::ExpanderRow::builder()
|
||||
.title(&b.created_at)
|
||||
.subtitle(&format!(
|
||||
@@ -1656,12 +1677,28 @@ fn build_backup_group(record_id: i64, toast_overlay: &adw::ToastOverlay) -> adw:
|
||||
row_clone.set_sensitive(true);
|
||||
match result {
|
||||
Ok(Ok(res)) => {
|
||||
let skip_note = if res.paths_skipped > 0 {
|
||||
format!(" ({} skipped)", res.paths_skipped)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
row_clone.set_subtitle(&format!(
|
||||
"Restored {} path{}",
|
||||
"Restored {} path{}{}",
|
||||
res.paths_restored,
|
||||
if res.paths_restored == 1 { "" } else { "s" },
|
||||
skip_note,
|
||||
));
|
||||
toast.add_toast(adw::Toast::new("Backup restored"));
|
||||
let toast_msg = format!(
|
||||
"Restored {} path{}{}",
|
||||
res.paths_restored,
|
||||
if res.paths_restored == 1 { "" } else { "s" },
|
||||
skip_note,
|
||||
);
|
||||
toast.add_toast(adw::Toast::new(&toast_msg));
|
||||
log::info!(
|
||||
"Backup restored: app={}, paths_restored={}, paths_skipped={}",
|
||||
res.manifest.app_name, res.paths_restored, res.paths_skipped,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
row_clone.set_subtitle("Restore failed");
|
||||
@@ -1922,7 +1959,9 @@ fn show_screenshot_lightbox(
|
||||
// --- Click outside image to close ---
|
||||
// Picture's gesture claims clicks on the image, preventing close.
|
||||
let pic_gesture = gtk::GestureClick::new();
|
||||
pic_gesture.connect_released(|_, _, _, _| {});
|
||||
pic_gesture.connect_released(|gesture, _, _, _| {
|
||||
gesture.set_state(gtk::EventSequenceState::Claimed);
|
||||
});
|
||||
picture.add_controller(pic_gesture);
|
||||
|
||||
// Window gesture fires for clicks on the dark margin area.
|
||||
|
||||
Reference in New Issue
Block a user