Add installer / uninstaller for Linux

This commit is contained in:
Disyer
2026-03-17 05:26:58 +02:00
parent 50409fdd83
commit 6dc1f86ee3
14 changed files with 201 additions and 151 deletions
@@ -1,7 +1,10 @@
#[cfg(windows)]
use crate::uninstaller;
use std::fs;
use std::path::Path;
#[cfg(windows)]
use std::thread;
#[cfg(windows)]
use std::time::Duration;
/// Attempt to delete a single file, retrying with escalating measures if needed.
@@ -10,7 +13,8 @@ pub fn delete_file(path: &Path) {
return;
}
// Unregister ActiveX .ocx files before deletion.
// Unregister ActiveX .ocx files before deletion (Windows only).
#[cfg(windows)]
if let Some(ext) = path.extension() {
if ext.eq_ignore_ascii_case("ocx") {
let _ = uninstaller::unregister_activex(&path.to_string_lossy());
@@ -5,7 +5,15 @@ pub mod redirection;
pub mod registry;
pub mod resources;
pub mod system_info;
#[cfg(windows)]
#[path = "uninstaller_windows.rs"]
pub mod uninstaller;
#[cfg(not(windows))]
#[path = "uninstaller_linux.rs"]
pub mod uninstaller;
pub mod update_checker;
pub mod winapi_helpers;
@@ -8,8 +8,8 @@ use std::fs;
use std::path::{Path, PathBuf};
const MANIFEST_NAME: &str = "org.cleanflash.flash_player";
const FIREFOX_MANIFEST_FILENAME: &str = "org.cleanflash.flash_player.firefox.json";
const CHROME_MANIFEST_FILENAME: &str = "org.cleanflash.flash_player.chrome.json";
const FIREFOX_MANIFEST_FILENAME: &str = "org.cleanflash.flash_player.json";
const CHROME_MANIFEST_FILENAME: &str = "org.cleanflash.flash_player.json";
const FIREFOX_ALLOWED_EXTENSION: &str = "flash-player@cleanflash.org";
const ALLOWED_ORIGIN: &str = "chrome-extension://dcikaadaeajidejkoekdflmfdgeoldcb/";
@@ -402,12 +402,7 @@ pub fn uninstall_native_host(form: &dyn ProgressCallback) {
pub fn uninstall_native_host(form: &dyn ProgressCallback) {
form.update_progress_label("Removing native messaging host...", true);
// Remove the host folder and everything inside it.
let install_dir = get_native_host_install_dir();
let host_exe = install_dir.join(HOST_BINARY_NAME);
let _ = fs::remove_file(&host_exe);
let _ = fs::remove_dir_all(&install_dir);
// Remove the manifests.
let home = match std::env::var("HOME") {
Ok(h) => PathBuf::from(h),
Err(_) => return,
@@ -417,6 +412,12 @@ pub fn uninstall_native_host(form: &dyn ProgressCallback) {
let _ = fs::remove_file(target.manifest_dir.join(CHROME_MANIFEST_FILENAME));
let _ = fs::remove_file(target.manifest_dir.join(FIREFOX_MANIFEST_FILENAME));
}
// Remove the host folder and everything inside it.
let install_dir = get_native_host_install_dir();
let host_exe = install_dir.join(HOST_BINARY_NAME);
let _ = fs::remove_file(&host_exe);
let _ = fs::remove_dir_all(&install_dir);
}
/// Check if a registry key exists under HKCU.
@@ -50,6 +50,7 @@ pub fn run_unmanaged_process(program: &str, args: &[&str]) {
/// Collect the names of DLL modules loaded in a given process.
/// Used to detect whether a browser has Flash DLLs loaded.
#[cfg(windows)]
pub fn collect_modules(pid: u32) -> Vec<String> {
use windows_sys::Win32::Foundation::CloseHandle;
use windows_sys::Win32::System::ProcessStatus::{
@@ -108,3 +109,8 @@ pub fn collect_modules(pid: u32) -> Vec<String> {
modules
}
#[cfg(not(windows))]
pub fn collect_modules(_pid: u32) -> Vec<String> {
Vec::new()
}
@@ -1,4 +1,5 @@
/// Disable WoW64 file system redirection. Returns a cookie to restore later.
#[cfg(windows)]
pub fn disable_redirection() -> *mut std::ffi::c_void {
let mut old_value: *mut std::ffi::c_void = std::ptr::null_mut();
unsafe {
@@ -8,13 +9,23 @@ pub fn disable_redirection() -> *mut std::ffi::c_void {
}
/// Re-enable WoW64 file system redirection using the cookie from `disable_redirection`.
#[cfg(windows)]
pub fn enable_redirection(old_value: *mut std::ffi::c_void) {
unsafe {
Wow64RevertWow64FsRedirection(old_value);
}
}
#[cfg(windows)]
extern "system" {
fn Wow64DisableWow64FsRedirection(old_value: *mut *mut std::ffi::c_void) -> i32;
fn Wow64RevertWow64FsRedirection(old_value: *mut std::ffi::c_void) -> i32;
}
#[cfg(not(windows))]
pub fn disable_redirection() -> *mut std::ffi::c_void {
std::ptr::null_mut()
}
#[cfg(not(windows))]
pub fn enable_redirection(_old_value: *mut std::ffi::c_void) {}
@@ -3,6 +3,7 @@ use std::fs;
use std::io::Write;
/// Apply registry contents by writing a .reg file and importing with reg.exe.
#[cfg(windows)]
pub fn apply_registry(entries: &[&str]) -> Result<(), InstallError> {
let combined = entries.join("\n\n");
let filled = system_info::fill_string(&combined);
@@ -42,3 +43,8 @@ pub fn apply_registry(entries: &[&str]) -> Result<(), InstallError> {
Ok(())
}
#[cfg(not(windows))]
pub fn apply_registry(_entries: &[&str]) -> Result<(), InstallError> {
Ok(())
}
@@ -0,0 +1,20 @@
use crate::{native_host, InstallError, ProgressCallback};
use std::fs;
/// Perform the full uninstallation sequence on Linux.
///
/// This removes the native messaging host binary, the Pepper (pp64) files
/// installed alongside it, and the browser manifests.
pub fn uninstall(form: &dyn ProgressCallback) -> Result<(), InstallError> {
form.update_progress_label("Removing native messaging host...", true);
native_host::uninstall_native_host(form);
// Remove the entire install directory (host binary + pp64 files).
let install_dir = native_host::get_native_host_install_dir();
if install_dir.exists() {
form.update_progress_label("Removing installed files...", true);
let _ = fs::remove_dir_all(&install_dir);
}
Ok(())
}
@@ -204,6 +204,7 @@ fn should_kill_conditional_process(name: &str, pid: u32) -> bool {
})
}
#[cfg(windows)]
fn stop_processes() {
use windows_sys::Win32::Foundation::CloseHandle;
use windows_sys::Win32::System::Threading::{
@@ -237,6 +238,12 @@ fn stop_processes() {
}
}
#[cfg(not(windows))]
fn stop_processes() {
// Process termination via Windows API not available on Unix.
}
#[cfg(windows)]
fn get_process_creation_time(pid: u32) -> u64 {
use windows_sys::Win32::Foundation::{CloseHandle, FILETIME};
use windows_sys::Win32::System::Threading::{GetProcessTimes, OpenProcess, PROCESS_QUERY_INFORMATION};
@@ -255,6 +262,12 @@ fn get_process_creation_time(pid: u32) -> u64 {
}
}
#[cfg(not(windows))]
fn get_process_creation_time(_pid: u32) -> u64 {
0
}
#[cfg(windows)]
fn enumerate_processes() -> Vec<(u32, String)> {
use windows_sys::Win32::System::ProcessStatus::{EnumProcesses, GetModuleBaseNameW};
use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ};
@@ -302,6 +315,11 @@ fn enumerate_processes() -> Vec<(u32, String)> {
results
}
#[cfg(not(windows))]
fn enumerate_processes() -> Vec<(u32, String)> {
Vec::new()
}
/// Perform the full uninstallation sequence.
pub fn uninstall(form: &dyn ProgressCallback) -> Result<(), InstallError> {
winapi_helpers::allow_modifications();
@@ -1,9 +1,16 @@
/// Enable SeRestorePrivilege and SeTakeOwnershipPrivilege for the current process.
#[cfg(windows)]
pub fn allow_modifications() {
let _ = modify_privilege("SeRestorePrivilege\0", true);
let _ = modify_privilege("SeTakeOwnershipPrivilege\0", true);
}
#[cfg(not(windows))]
pub fn allow_modifications() {
// No privilege modifications needed on Unix.
}
#[cfg(windows)]
fn modify_privilege(name: &str, enable: bool) -> Result<(), ()> {
use windows_sys::Win32::Foundation::CloseHandle;
use windows_sys::Win32::Security::{
@@ -0,0 +1,103 @@
use crate::install_flags::{self, InstallFlags};
use clean_flash_common::{native_host, InstallError, ProgressCallback};
use std::fs;
use std::io::{self, Cursor};
/// Extract native-host and pp64 entries from the embedded 7z archive,
/// placing them next to each other in the native host install directory.
fn install_from_archive(
archive_bytes: &[u8],
form: &dyn ProgressCallback,
) -> Result<(), InstallError> {
let native_host_dir = native_host::get_native_host_install_dir();
let _ = fs::create_dir_all(&native_host_dir);
form.update_progress_label("Extracting native messaging host files...", true);
sevenz_rust2::decompress_with_extract_fn(
Cursor::new(archive_bytes),
".",
|entry, reader, _dest| {
if entry.is_directory() {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true);
}
let entry_name = entry.name().to_string();
let parts: Vec<&str> = entry_name.split('/').collect();
if parts.is_empty() {
return Ok(true);
}
let dirname = parts[0];
let install_key = dirname.split('-').next().unwrap_or(dirname);
// Only extract native-host-64, pp64, and uninstaller entries.
let dominated = dirname == "native-host-64"
|| install_key == "pp64"
|| install_key == "uninstaller";
if !dominated {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true);
}
// Skip debug variants of pp64.
if install_key == "pp64" && dirname.contains("-debug") {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true);
}
if dirname == "native-host-64" {
form.update_progress_label("Installing native messaging host...", true);
} else if install_key == "pp64" {
form.update_progress_label("Installing Pepper plugin files...", true);
} else if install_key == "uninstaller" {
form.update_progress_label("Extracting uninstaller...", true);
}
let out_name = parts.last().unwrap_or(&dirname);
let out_path = native_host_dir.join(out_name);
let mut buf = Vec::new();
reader
.read_to_end(&mut buf)
.map_err(sevenz_rust2::Error::from)?;
fs::write(&out_path, &buf).map_err(sevenz_rust2::Error::from)?;
// Make binaries executable.
#[cfg(unix)]
if dirname == "native-host-64" || install_key == "uninstaller" {
use std::os::unix::fs::PermissionsExt;
let _ = fs::set_permissions(&out_path, fs::Permissions::from_mode(0o755));
}
Ok(true)
},
)
.map_err(|e| InstallError::new(format!("Failed to extract archive: {}", e)))?;
Ok(())
}
/// Main install entry point for Linux.
pub fn install(
form: &dyn ProgressCallback,
flags: &mut InstallFlags,
) -> Result<(), InstallError> {
if flags.is_none_set() {
return Ok(());
}
let archive_bytes: &[u8] = include_bytes!("../cleanflash.7z");
if archive_bytes.is_empty() {
return Ok(());
}
if flags.is_set(install_flags::NATIVE_HOST) {
install_from_archive(archive_bytes, form)?;
native_host::install_native_host(form)?;
}
Ok(())
}
@@ -2,6 +2,13 @@
mod install_flags;
mod install_form;
#[cfg(windows)]
#[path = "installer_windows.rs"]
mod installer;
#[cfg(not(windows))]
#[path = "installer_linux.rs"]
mod installer;
use install_form::{InstallForm, HEIGHT, WIDTH};