Install native host

master
darktohka 6 days ago
parent 202e2c160f
commit 50409fdd83

@ -21,6 +21,7 @@ windows-sys = { version = "0.61", features = [
"Win32_System_Threading", "Win32_System_Threading",
"Win32_System_ProcessStatus", "Win32_System_ProcessStatus",
"Win32_Storage_FileSystem", "Win32_Storage_FileSystem",
"Win32_System_Registry",
"Win32_System_SystemInformation", "Win32_System_SystemInformation",
"Win32_UI_HiDpi", "Win32_UI_HiDpi",
"Win32_UI_Shell", "Win32_UI_Shell",

@ -1,4 +1,5 @@
pub mod file_util; pub mod file_util;
pub mod native_host;
pub mod process_utils; pub mod process_utils;
pub mod redirection; pub mod redirection;
pub mod registry; pub mod registry;

@ -0,0 +1,444 @@
//! Install and uninstall the native messaging host for modern browsers.
//!
//! The native messaging host allows the Clean Flash Player browser extension
//! to communicate with the local flash-player-host binary via stdio.
use crate::{InstallError, ProgressCallback};
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_ALLOWED_EXTENSION: &str = "flash-player@cleanflash.org";
const ALLOWED_ORIGIN: &str = "chrome-extension://dcikaadaeajidejkoekdflmfdgeoldcb/";
#[cfg(windows)]
const HOST_BINARY_NAME: &str = "flash-player-host.exe";
#[cfg(not(windows))]
const HOST_BINARY_NAME: &str = "flash-player-host";
#[derive(Clone, Copy)]
enum BrowserKind {
Firefox,
ChromeLike,
}
#[cfg(windows)]
struct WindowsBrowser {
detect_keys: &'static [&'static str],
native_messaging_reg_path: &'static str,
kind: BrowserKind,
}
/// Browser registry key paths on Windows (HKCU/HKLM) for native messaging hosts.
#[cfg(windows)]
const WINDOWS_BROWSERS: &[WindowsBrowser] = &[
WindowsBrowser {
detect_keys: &[r"SOFTWARE\Google\Chrome"],
native_messaging_reg_path: r"SOFTWARE\Google\Chrome\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\Microsoft\Edge"],
native_messaging_reg_path: r"SOFTWARE\Microsoft\Edge\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\BraveSoftware\Brave-Browser"],
native_messaging_reg_path: r"SOFTWARE\BraveSoftware\Brave-Browser\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\Vivaldi"],
native_messaging_reg_path: r"SOFTWARE\Vivaldi\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\Opera Software"],
native_messaging_reg_path: r"SOFTWARE\Opera Software\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\Chromium"],
native_messaging_reg_path: r"SOFTWARE\Chromium\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\The Browser Company\Arc"],
native_messaging_reg_path: r"SOFTWARE\The Browser Company\Arc\NativeMessagingHosts",
kind: BrowserKind::ChromeLike,
},
WindowsBrowser {
detect_keys: &[r"SOFTWARE\Mozilla\Mozilla Firefox", r"SOFTWARE\Mozilla"],
native_messaging_reg_path: r"SOFTWARE\Mozilla\NativeMessagingHosts",
kind: BrowserKind::Firefox,
},
];
struct BrowserManifestTarget {
detect_path: PathBuf,
manifest_dir: PathBuf,
kind: BrowserKind,
}
/// Build the JSON manifest content for the native messaging host.
fn build_manifest_json(host_path: &Path, kind: BrowserKind) -> String {
// Escape backslashes in the path for JSON.
let path_str = host_path.to_string_lossy().replace('\\', "\\\\");
match kind {
BrowserKind::Firefox => format!(
"{{\n \"name\": \"{}\",\n \"description\": \"Flash Player Native Messaging Host\",\n \"path\": \"{}\",\n \"type\": \"stdio\",\n \"allowed_extensions\": [\"{}\"]\n}}\n",
MANIFEST_NAME, path_str, FIREFOX_ALLOWED_EXTENSION,
),
BrowserKind::ChromeLike => format!(
"{{\n \"name\": \"{}\",\n \"description\": \"Flash Player Native Messaging Host\",\n \"path\": \"{}\",\n \"type\": \"stdio\",\n \"allowed_origins\": [\"{}\"]\n}}\n",
MANIFEST_NAME, path_str, ALLOWED_ORIGIN,
),
}
}
/// Get the path where the native host exe should be installed on Windows.
/// On a 64-bit system it goes into the System32\Macromed\Flash folder (the 64-bit one).
/// On a 32-bit system it goes into the SysWOW64 (or System32) Macromed\Flash folder.
#[cfg(windows)]
pub fn get_native_host_install_dir() -> PathBuf {
crate::system_info::with_system_info(|si| {
if si.is_64bit {
si.flash64_path.clone()
} else {
si.flash32_path.clone()
}
})
}
#[cfg(not(windows))]
pub fn get_native_host_install_dir() -> PathBuf {
if cfg!(target_os = "macos") {
PathBuf::from("/Library/Application Support/Clean Flash")
} else {
// Linux
if let Ok(home) = std::env::var("HOME") {
PathBuf::from(home).join(".cleanflash")
} else {
PathBuf::from("/tmp/.cleanflash")
}
}
}
/// Get the full path to the installed native host executable.
pub fn get_native_host_exe_path() -> PathBuf {
get_native_host_install_dir().join(HOST_BINARY_NAME)
}
fn manifest_filename_for_kind(kind: BrowserKind) -> &'static str {
match kind {
BrowserKind::Firefox => FIREFOX_MANIFEST_FILENAME,
BrowserKind::ChromeLike => CHROME_MANIFEST_FILENAME,
}
}
#[cfg(not(windows))]
fn get_non_windows_browser_targets(home: &Path) -> Vec<BrowserManifestTarget> {
if cfg!(target_os = "macos") {
vec![
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/Google/Chrome"),
manifest_dir: home.join("Library/Application Support/Google/Chrome/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/Microsoft Edge"),
manifest_dir: home.join("Library/Application Support/Microsoft Edge/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/BraveSoftware/Brave-Browser"),
manifest_dir: home.join("Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/Vivaldi"),
manifest_dir: home.join("Library/Application Support/Vivaldi/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/Chromium"),
manifest_dir: home.join("Library/Application Support/Chromium/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/Arc"),
manifest_dir: home.join("Library/Application Support/Arc/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join("Library/Application Support/Mozilla"),
manifest_dir: home.join("Library/Application Support/Mozilla/NativeMessagingHosts"),
kind: BrowserKind::Firefox,
},
]
} else {
vec![
BrowserManifestTarget {
detect_path: home.join(".config/google-chrome"),
manifest_dir: home.join(".config/google-chrome/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join(".config/microsoft-edge"),
manifest_dir: home.join(".config/microsoft-edge/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join(".config/BraveSoftware/Brave-Browser"),
manifest_dir: home.join(".config/BraveSoftware/Brave-Browser/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join(".config/vivaldi"),
manifest_dir: home.join(".config/vivaldi/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join(".config/chromium"),
manifest_dir: home.join(".config/chromium/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join(".config/arc"),
manifest_dir: home.join(".config/arc/NativeMessagingHosts"),
kind: BrowserKind::ChromeLike,
},
BrowserManifestTarget {
detect_path: home.join(".mozilla"),
manifest_dir: home.join(".mozilla/native-messaging-hosts"),
kind: BrowserKind::Firefox,
},
]
}
}
#[cfg(windows)]
fn set_windows_manifest_registry_value(nmh_base_key: &str, manifest_path: &str) {
use windows_sys::Win32::System::Registry::{
RegCloseKey, RegCreateKeyExW, RegSetValueExW, HKEY_CURRENT_USER,
KEY_WOW64_64KEY, KEY_WRITE, REG_OPTION_NON_VOLATILE, REG_SZ,
};
let reg_key = format!("{}\\{}", nmh_base_key, MANIFEST_NAME);
let key_wide: Vec<u16> = reg_key.encode_utf16().chain(std::iter::once(0)).collect();
let val_wide: Vec<u16> = manifest_path
.encode_utf16()
.chain(std::iter::once(0))
.collect();
unsafe {
let mut hkey = std::ptr::null_mut();
let mut disposition: u32 = 0;
let result = RegCreateKeyExW(
HKEY_CURRENT_USER,
key_wide.as_ptr(),
0,
std::ptr::null(),
REG_OPTION_NON_VOLATILE,
KEY_WRITE | KEY_WOW64_64KEY,
std::ptr::null(),
&mut hkey,
&mut disposition,
);
if result == 0 {
RegSetValueExW(
hkey,
std::ptr::null(),
0,
REG_SZ as u32,
val_wide.as_ptr() as *const u8,
(val_wide.len() * 2) as u32,
);
RegCloseKey(hkey);
}
}
}
#[cfg(windows)]
fn delete_windows_manifest_registry_value(nmh_base_key: &str) {
use windows_sys::Win32::System::Registry::{
RegCloseKey, RegDeleteTreeW, RegOpenKeyExW, HKEY_CURRENT_USER,
KEY_WOW64_64KEY, KEY_WRITE,
};
unsafe {
let parent_wide: Vec<u16> = nmh_base_key
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let name_wide: Vec<u16> = MANIFEST_NAME
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let mut parent_hkey = std::ptr::null_mut();
let result = RegOpenKeyExW(
HKEY_CURRENT_USER,
parent_wide.as_ptr(),
0,
KEY_WRITE | KEY_WOW64_64KEY,
&mut parent_hkey,
);
if result == 0 {
RegDeleteTreeW(parent_hkey, name_wide.as_ptr());
RegCloseKey(parent_hkey);
}
}
}
/// Install the native messaging host manifests for all detected browsers.
#[cfg(windows)]
pub fn install_native_host(form: &dyn ProgressCallback) -> Result<(), InstallError> {
form.update_progress_label("Installing native messaging host for modern browsers...", true);
let host_exe = get_native_host_exe_path();
let chrome_manifest_json = build_manifest_json(&host_exe, BrowserKind::ChromeLike);
let firefox_manifest_json = build_manifest_json(&host_exe, BrowserKind::Firefox);
// Create manifest directory inside the install dir.
let manifest_dir = get_native_host_install_dir().join("manifests");
let _ = fs::create_dir_all(&manifest_dir);
let chrome_manifest_path = manifest_dir.join(CHROME_MANIFEST_FILENAME);
fs::write(&chrome_manifest_path, chrome_manifest_json.as_bytes()).map_err(|e| {
InstallError::new(format!(
"Failed to write Chrome native messaging manifest: {}",
e
))
})?;
let firefox_manifest_path = manifest_dir.join(FIREFOX_MANIFEST_FILENAME);
fs::write(&firefox_manifest_path, firefox_manifest_json.as_bytes()).map_err(|e| {
InstallError::new(format!(
"Failed to write Firefox native messaging manifest: {}",
e
))
})?;
let chrome_manifest_path_str = chrome_manifest_path.to_string_lossy().to_string();
let firefox_manifest_path_str = firefox_manifest_path.to_string_lossy().to_string();
// For each browser that is detected via registry, register the manifest.
for browser in WINDOWS_BROWSERS {
if !browser
.detect_keys
.iter()
.any(|detect_key| windows_registry_key_exists(detect_key))
{
continue;
}
let manifest_path = match browser.kind {
BrowserKind::Firefox => &firefox_manifest_path_str,
BrowserKind::ChromeLike => &chrome_manifest_path_str,
};
set_windows_manifest_registry_value(browser.native_messaging_reg_path, manifest_path);
}
Ok(())
}
#[cfg(not(windows))]
pub fn install_native_host(form: &dyn ProgressCallback) -> Result<(), InstallError> {
form.update_progress_label("Installing native messaging host for modern browsers...", true);
let host_exe = get_native_host_exe_path();
let chrome_manifest_json = build_manifest_json(&host_exe, BrowserKind::ChromeLike);
let firefox_manifest_json = build_manifest_json(&host_exe, BrowserKind::Firefox);
// Determine browser config directories that exist.
let home = std::env::var("HOME")
.map_err(|_| InstallError::new("HOME environment variable not set"))?;
let home = PathBuf::from(home);
// Check known browser paths and install manifests only for those that exist.
for target in get_non_windows_browser_targets(&home) {
if !target.detect_path.exists() {
continue;
}
let _ = fs::create_dir_all(&target.manifest_dir);
let manifest_filename = manifest_filename_for_kind(target.kind);
let manifest_json = match target.kind {
BrowserKind::Firefox => &firefox_manifest_json,
BrowserKind::ChromeLike => &chrome_manifest_json,
};
let manifest_path = target.manifest_dir.join(manifest_filename);
let _ = fs::write(&manifest_path, manifest_json.as_bytes());
}
Ok(())
}
/// Uninstall the native messaging host: remove manifests and registry entries.
#[cfg(windows)]
pub fn uninstall_native_host(form: &dyn ProgressCallback) {
form.update_progress_label("Removing native messaging host...", true);
// Remove manifest files.
let install_dir = get_native_host_install_dir();
let manifest_dir = install_dir.join("manifests");
let _ = fs::remove_file(manifest_dir.join(CHROME_MANIFEST_FILENAME));
let _ = fs::remove_file(manifest_dir.join(FIREFOX_MANIFEST_FILENAME));
let _ = fs::remove_dir(&manifest_dir);
// Remove the host exe.
let host_exe = install_dir.join(HOST_BINARY_NAME);
crate::file_util::delete_file(&host_exe);
// Remove registry entries for all browsers.
for browser in WINDOWS_BROWSERS {
delete_windows_manifest_registry_value(browser.native_messaging_reg_path);
}
}
#[cfg(not(windows))]
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);
let home = match std::env::var("HOME") {
Ok(h) => PathBuf::from(h),
Err(_) => return,
};
for target in get_non_windows_browser_targets(&home) {
let _ = fs::remove_file(target.manifest_dir.join(CHROME_MANIFEST_FILENAME));
let _ = fs::remove_file(target.manifest_dir.join(FIREFOX_MANIFEST_FILENAME));
}
}
/// Check if a registry key exists under HKCU.
#[cfg(windows)]
fn windows_registry_key_exists(subkey: &str) -> bool {
use windows_sys::Win32::System::Registry::{
RegCloseKey, RegOpenKeyExW, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE,
KEY_READ, KEY_WOW64_64KEY,
};
let key_wide: Vec<u16> = subkey.encode_utf16().chain(std::iter::once(0)).collect();
// Check HKCU first, then HKLM.
for &root in &[HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE] {
unsafe {
let mut hkey = std::ptr::null_mut();
let result = RegOpenKeyExW(root, key_wide.as_ptr(), 0, KEY_READ | KEY_WOW64_64KEY, &mut hkey);
if result == 0 {
RegCloseKey(hkey);
return true;
}
}
}
false
}

@ -1,5 +1,5 @@
use crate::{ use crate::{
file_util, process_utils, registry, resources, system_info, winapi_helpers, InstallError, file_util, native_host, process_utils, registry, resources, system_info, winapi_helpers, InstallError,
ProgressCallback, ProgressCallback,
}; };
use std::env; use std::env;
@ -21,6 +21,7 @@ const PROCESSES_TO_KILL: &[&str] = &[
"flashplayerapp", "flashplayerapp",
"flashplayer_sa", "flashplayer_sa",
"flashplayer_sa_debug", "flashplayer_sa_debug",
"flash-player-host",
]; ];
const CONDITIONAL_PROCESSES: &[&str] = &[ const CONDITIONAL_PROCESSES: &[&str] = &[
@ -329,6 +330,8 @@ pub fn uninstall(form: &dyn ProgressCallback) -> Result<(), InstallError> {
form.update_progress_label("Removing Flash Player...", true); form.update_progress_label("Removing Flash Player...", true);
delete_flash_player(); delete_flash_player();
native_host::uninstall_native_host(form);
Ok(()) Ok(())
} }

@ -9,8 +9,9 @@ pub const PLAYER_START_MENU: u32 = 1 << 4;
pub const PLAYER_DESKTOP: u32 = 1 << 5; pub const PLAYER_DESKTOP: u32 = 1 << 5;
pub const X64: u32 = 1 << 6; pub const X64: u32 = 1 << 6;
pub const DEBUG: u32 = 1 << 7; pub const DEBUG: u32 = 1 << 7;
pub const NATIVE_HOST: u32 = 1 << 8;
const UNINSTALL_TICKS: u32 = 9; const UNINSTALL_TICKS: u32 = 10;
const INSTALL_GENERAL_TICKS: u32 = 5; const INSTALL_GENERAL_TICKS: u32 = 5;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -65,6 +66,10 @@ impl InstallFlags {
ticks += 1; ticks += 1;
} }
if self.is_set(NATIVE_HOST) {
ticks += 1;
}
ticks += UNINSTALL_TICKS; ticks += UNINSTALL_TICKS;
ticks += INSTALL_GENERAL_TICKS; ticks += INSTALL_GENERAL_TICKS;
ticks ticks

@ -26,6 +26,10 @@ const COMPLETE_INSTALL_TEXT: &str = "Clean Flash Player has been successfully in
Don't forget, Flash Player is no longer compatible with new browsers.\n\n\ Don't forget, Flash Player is no longer compatible with new browsers.\n\n\
For browser recommendations and Flash Player updates, check out Clean Flash Player's website!"; For browser recommendations and Flash Player updates, check out Clean Flash Player's website!";
const COMPLETE_INSTALL_WITH_EXTENSION_TEXT: &str = "Clean Flash Player has been successfully installed!\n\n\
To use Flash in modern browsers, install the Clean Flash Player extension into your browser.\n\n\
For Flash Player updates, check out Clean Flash Player's website!";
const COMPLETE_UNINSTALL_TEXT: &str = "\nAll versions of Flash Player have been successfully uninstalled.\n\n\ const COMPLETE_UNINSTALL_TEXT: &str = "\nAll versions of Flash Player have been successfully uninstalled.\n\n\
If you ever change your mind, check out Clean Flash Player's website!"; If you ever change your mind, check out Clean Flash Player's website!";
@ -66,6 +70,8 @@ pub struct InstallForm {
pub disclaimer_box: ImageCheckBox, pub disclaimer_box: ImageCheckBox,
// Choice panel (browser plugins) // Choice panel (browser plugins)
pub browser_ask_label: Label, pub browser_ask_label: Label,
pub native_host_box: ImageCheckBox,
pub native_host_label: Label,
pub pepper_box: ImageCheckBox, pub pepper_box: ImageCheckBox,
pub pepper_label: Label, pub pepper_label: Label,
pub netscape_box: ImageCheckBox, pub netscape_box: ImageCheckBox,
@ -130,7 +136,7 @@ impl InstallForm {
let fonts = FontManager::new(); let fonts = FontManager::new();
Self { let mut form = Self {
scale, scale,
panel: Panel::Disclaimer, panel: Panel::Disclaimer,
title_text, title_text,
@ -143,12 +149,14 @@ impl InstallForm {
disclaimer_box: chk(PANEL_X, PANEL_Y), disclaimer_box: chk(PANEL_X, PANEL_Y),
// Choice panel // Choice panel
browser_ask_label: lbl(PANEL_X - 2, PANEL_Y + 2, "Which browser plugins would you like to install?", 15.0), browser_ask_label: lbl(PANEL_X - 2, PANEL_Y + 2, "Which browser plugins would you like to install?", 15.0),
pepper_box: chk(PANEL_X, PANEL_Y + 47), native_host_box: chk(PANEL_X, PANEL_Y + 27),
pepper_label: lbl(PANEL_X + 24, PANEL_Y + 47, "Pepper API (PPAPI)\n(Chrome/Opera/Brave)", 15.0), native_host_label: lbl(PANEL_X + 24, PANEL_Y + 27, "Modern Browsers (MV3)\n(Chrome/Firefox/Edge)", 15.0),
netscape_box: chk(PANEL_X + 186, PANEL_Y + 47), pepper_box: chk(PANEL_X, PANEL_Y + 73),
netscape_label: lbl(PANEL_X + 210, PANEL_Y + 47, "Netscape API (NPAPI)\n(Firefox/ESR/Waterfox)", 15.0), pepper_label: lbl(PANEL_X + 24, PANEL_Y + 73, "Pepper API (PPAPI)\n(Chrome/Opera/Brave)", 15.0),
activex_box: chk(PANEL_X + 365, PANEL_Y + 47), netscape_box: chk(PANEL_X + 186, PANEL_Y + 73),
activex_label: lbl(PANEL_X + 389, PANEL_Y + 47, "ActiveX (OCX)\n(IE/Embedded/Desktop)", 15.0), netscape_label: lbl(PANEL_X + 210, PANEL_Y + 73, "Netscape API (NPAPI)\n(Firefox/ESR/Waterfox)", 15.0),
activex_box: chk(PANEL_X + 365, PANEL_Y + 73),
activex_label: lbl(PANEL_X + 389, PANEL_Y + 73, "ActiveX (OCX)\n(IE/Embedded/Desktop)", 15.0),
// Player choice panel // Player choice panel
player_ask_label: lbl(PANEL_X - 2, PANEL_Y + 2, "Would you like to install the standalone Flash Player?", 15.0), player_ask_label: lbl(PANEL_X - 2, PANEL_Y + 2, "Would you like to install the standalone Flash Player?", 15.0),
player_box: chk(PANEL_X, PANEL_Y + 47), player_box: chk(PANEL_X, PANEL_Y + 47),
@ -194,7 +202,29 @@ The following details could be useful. Press the Retry button to try again.",
})), })),
fonts, fonts,
prev_mouse_down: false, prev_mouse_down: false,
};
// Modern browser support should be the default choice.
form.native_host_box.checked = true;
// On non-Windows platforms, disable legacy browser plugins and player options.
#[cfg(not(target_os = "windows"))]
{
form.pepper_box.checked = false;
form.pepper_box.enabled = false;
form.netscape_box.checked = false;
form.netscape_box.enabled = false;
form.activex_box.checked = false;
form.activex_box.enabled = false;
form.player_box.checked = false;
form.player_box.enabled = false;
form.player_desktop_box.checked = false;
form.player_desktop_box.enabled = false;
form.player_start_menu_box.checked = false;
form.player_start_menu_box.enabled = false;
} }
form
} }
/// Scale a logical integer coordinate to physical pixels. /// Scale a logical integer coordinate to physical pixels.
@ -296,16 +326,30 @@ The following details could be useful. Press the Retry button to try again.",
} }
} }
Panel::Choice => { Panel::Choice => {
self.native_host_box.toggle_if_clicked(mx, my, mouse_released);
self.pepper_box.toggle_if_clicked(mx, my, mouse_released); self.pepper_box.toggle_if_clicked(mx, my, mouse_released);
self.netscape_box.toggle_if_clicked(mx, my, mouse_released); self.netscape_box.toggle_if_clicked(mx, my, mouse_released);
self.activex_box.toggle_if_clicked(mx, my, mouse_released); self.activex_box.toggle_if_clicked(mx, my, mouse_released);
if self.pepper_label.clicked(mx, my, mouse_released, &self.fonts) { if self.native_host_box.enabled
&& self
.native_host_label
.clicked(mx, my, mouse_released, &self.fonts)
{
self.native_host_box.checked = !self.native_host_box.checked;
}
if self.pepper_box.enabled
&& self.pepper_label.clicked(mx, my, mouse_released, &self.fonts)
{
self.pepper_box.checked = !self.pepper_box.checked; self.pepper_box.checked = !self.pepper_box.checked;
} }
if self.netscape_label.clicked(mx, my, mouse_released, &self.fonts) { if self.netscape_box.enabled
&& self.netscape_label.clicked(mx, my, mouse_released, &self.fonts)
{
self.netscape_box.checked = !self.netscape_box.checked; self.netscape_box.checked = !self.netscape_box.checked;
} }
if self.activex_label.clicked(mx, my, mouse_released, &self.fonts) { if self.activex_box.enabled
&& self.activex_label.clicked(mx, my, mouse_released, &self.fonts)
{
self.activex_box.checked = !self.activex_box.checked; self.activex_box.checked = !self.activex_box.checked;
} }
} }
@ -313,13 +357,25 @@ The following details could be useful. Press the Retry button to try again.",
self.player_box.toggle_if_clicked(mx, my, mouse_released); self.player_box.toggle_if_clicked(mx, my, mouse_released);
self.player_desktop_box.toggle_if_clicked(mx, my, mouse_released); self.player_desktop_box.toggle_if_clicked(mx, my, mouse_released);
self.player_start_menu_box.toggle_if_clicked(mx, my, mouse_released); self.player_start_menu_box.toggle_if_clicked(mx, my, mouse_released);
if self.player_label.clicked(mx, my, mouse_released, &self.fonts) { if self.player_box.enabled
&& self.player_label.clicked(mx, my, mouse_released, &self.fonts)
{
self.player_box.checked = !self.player_box.checked; self.player_box.checked = !self.player_box.checked;
} }
if self.player_desktop_label.clicked(mx, my, mouse_released, &self.fonts) && self.player_box.checked { if self.player_desktop_box.enabled
&& self
.player_desktop_label
.clicked(mx, my, mouse_released, &self.fonts)
&& self.player_box.checked
{
self.player_desktop_box.checked = !self.player_desktop_box.checked; self.player_desktop_box.checked = !self.player_desktop_box.checked;
} }
if self.player_start_menu_label.clicked(mx, my, mouse_released, &self.fonts) && self.player_box.checked { if self.player_start_menu_box.enabled
&& self
.player_start_menu_label
.clicked(mx, my, mouse_released, &self.fonts)
&& self.player_box.checked
{
self.player_start_menu_box.checked = !self.player_start_menu_box.checked; self.player_start_menu_box.checked = !self.player_start_menu_box.checked;
} }
// Disable sub-options when player unchecked. // Disable sub-options when player unchecked.
@ -359,7 +415,13 @@ The following details could be useful. Press the Retry button to try again.",
Panel::Choice => self.open_disclaimer(), Panel::Choice => self.open_disclaimer(),
Panel::PlayerChoice => self.open_choice(), Panel::PlayerChoice => self.open_choice(),
Panel::DebugChoice => self.open_player_choice(), Panel::DebugChoice => self.open_player_choice(),
Panel::BeforeInstall => self.open_debug_choice(), Panel::BeforeInstall => {
if cfg!(target_os = "windows") {
self.open_debug_choice();
} else {
self.open_choice();
}
}
_ => {} _ => {}
} }
} }
@ -367,7 +429,13 @@ The following details could be useful. Press the Retry button to try again.",
fn on_next_clicked(&mut self) { fn on_next_clicked(&mut self) {
match self.panel { match self.panel {
Panel::Disclaimer => self.open_choice(), Panel::Disclaimer => self.open_choice(),
Panel::Choice => self.open_player_choice(), Panel::Choice => {
if cfg!(target_os = "windows") {
self.open_player_choice();
} else {
self.open_before_install();
}
}
Panel::PlayerChoice => self.open_debug_choice(), Panel::PlayerChoice => self.open_debug_choice(),
Panel::DebugChoice => self.open_before_install(), Panel::DebugChoice => self.open_before_install(),
Panel::BeforeInstall | Panel::Failure => self.open_install(), Panel::BeforeInstall | Panel::Failure => self.open_install(),
@ -418,10 +486,13 @@ The following details could be useful. Press the Retry button to try again.",
self.prev_button.enabled = true; self.prev_button.enabled = true;
let has_plugins = let has_plugins =
self.pepper_box.checked || self.netscape_box.checked || self.activex_box.checked || self.player_box.checked; self.native_host_box.checked || self.pepper_box.checked || self.netscape_box.checked || self.activex_box.checked || self.player_box.checked;
if has_plugins { if has_plugins {
let mut browsers = Vec::new(); let mut browsers = Vec::new();
if self.native_host_box.checked {
browsers.push("Modern Browsers (via extension)");
}
if self.pepper_box.checked { if self.pepper_box.checked {
browsers.push("Google Chrome"); browsers.push("Google Chrome");
} }
@ -458,6 +529,7 @@ The installer will completely remove all versions of Flash Player from this comp
self.next_button.visible = false; self.next_button.visible = false;
let mut flags = InstallFlags::new(); let mut flags = InstallFlags::new();
flags.set_conditionally(self.native_host_box.checked, install_flags::NATIVE_HOST);
flags.set_conditionally(self.pepper_box.checked, install_flags::PEPPER); flags.set_conditionally(self.pepper_box.checked, install_flags::PEPPER);
flags.set_conditionally(self.netscape_box.checked, install_flags::NETSCAPE); flags.set_conditionally(self.netscape_box.checked, install_flags::NETSCAPE);
flags.set_conditionally(self.activex_box.checked, install_flags::ACTIVEX); flags.set_conditionally(self.activex_box.checked, install_flags::ACTIVEX);
@ -529,7 +601,9 @@ The installer will completely remove all versions of Flash Player from this comp
self.prev_button.enabled = true; self.prev_button.enabled = true;
self.next_button.visible = false; self.next_button.visible = false;
if self.pepper_box.checked || self.netscape_box.checked || self.activex_box.checked { if self.native_host_box.checked {
self.complete_label.text = COMPLETE_INSTALL_WITH_EXTENSION_TEXT.to_string();
} else if self.pepper_box.checked || self.netscape_box.checked || self.activex_box.checked {
self.complete_label.text = COMPLETE_INSTALL_TEXT.to_string(); self.complete_label.text = COMPLETE_INSTALL_TEXT.to_string();
} else { } else {
self.complete_label.text = COMPLETE_UNINSTALL_TEXT.to_string(); self.complete_label.text = COMPLETE_UNINSTALL_TEXT.to_string();
@ -553,6 +627,8 @@ The installer will completely remove all versions of Flash Player from this comp
fn draw_choice(&self, r: &mut Renderer) { fn draw_choice(&self, r: &mut Renderer) {
self.browser_ask_label.draw(r, &self.fonts); self.browser_ask_label.draw(r, &self.fonts);
self.native_host_box.draw(r);
self.native_host_label.draw(r, &self.fonts);
self.pepper_box.draw(r); self.pepper_box.draw(r);
self.pepper_label.draw(r, &self.fonts); self.pepper_label.draw(r, &self.fonts);
self.netscape_box.draw(r); self.netscape_box.draw(r);

@ -1,6 +1,6 @@
use crate::install_flags::{self, InstallFlags}; use crate::install_flags::{self, InstallFlags};
use clean_flash_common::{ use clean_flash_common::{
process_utils, registry, resources, system_info, InstallError, ProgressCallback, native_host, process_utils, registry, resources, system_info, InstallError, ProgressCallback,
}; };
use std::env; use std::env;
use std::fs; use std::fs;
@ -89,6 +89,7 @@ fn install_from_archive(
let flash64_path = si.flash64_path.clone(); let flash64_path = si.flash64_path.clone();
let system32_path = si.system32_path.clone(); let system32_path = si.system32_path.clone();
let flash_program32_path = si.flash_program32_path.clone(); let flash_program32_path = si.flash_program32_path.clone();
let native_host_dir = native_host::get_native_host_install_dir();
let mut registry_to_apply: Vec<&str> = vec![resources::INSTALL_GENERAL]; let mut registry_to_apply: Vec<&str> = vec![resources::INSTALL_GENERAL];
@ -179,6 +180,24 @@ fn install_from_archive(
registry_instructions: Some(resources::INSTALL_PP_64), registry_instructions: Some(resources::INSTALL_PP_64),
}, },
), ),
(
"native-host-64",
InstallEntry {
install_text: "Installing native messaging host (64-bit)...",
required_flags: install_flags::NATIVE_HOST | install_flags::X64,
target_directory: native_host_dir.clone(),
registry_instructions: None,
},
),
(
"native-host-32",
InstallEntry {
install_text: "Installing native messaging host (32-bit)...",
required_flags: install_flags::NATIVE_HOST,
target_directory: native_host_dir.clone(),
registry_instructions: None,
},
),
]; ];
let legacy = si.is_legacy_windows(); let legacy = si.is_legacy_windows();
@ -202,24 +221,48 @@ fn install_from_archive(
let filename = parts[0]; let filename = parts[0];
let install_key = filename.split('-').next().unwrap_or(filename); let install_key = filename.split('-').next().unwrap_or(filename);
let is_pp32 = install_key == "pp32";
// Find the matching entry. let is_pp64 = install_key == "pp64";
let Some((_key, install_entry)) = entries.iter().find(|(k, _)| *k == install_key) let should_extract_pepper_for_native_host =
flags.is_set(install_flags::NATIVE_HOST)
&& ((si.is_64bit && is_pp64) || (!si.is_64bit && is_pp32));
// Find the matching entry: try exact match on full dirname first,
// then fall back to first segment before '-'.
let Some((_key, install_entry)) = entries
.iter()
.find(|(k, _)| *k == filename)
.or_else(|| entries.iter().find(|(k, _)| *k == install_key))
else { else {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?; io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true); return Ok(true);
}; };
// Check required flags. // Check required flags.
let should_install_by_flags = install_entry.required_flags == install_flags::NONE
|| flags.is_set(install_entry.required_flags);
if install_entry.required_flags != install_flags::NONE if install_entry.required_flags != install_flags::NONE
&& !flags.is_set(install_entry.required_flags) && !flags.is_set(install_entry.required_flags)
&& !(should_extract_pepper_for_native_host && (is_pp32 || is_pp64))
{ {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?; io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true); return Ok(true);
} }
// Check debug flag match. // For native-host: on 64-bit use only native-host-64, on 32-bit use only native-host-32.
if install_entry.required_flags != install_flags::NONE { if filename == "native-host-32" && si.is_64bit {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true);
}
if filename == "native-host-64" && !si.is_64bit {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
return Ok(true);
}
// Check debug flag match (skip native-host entries from this check).
if install_entry.required_flags != install_flags::NONE
&& (install_entry.required_flags & install_flags::NATIVE_HOST) == 0
{
let is_debug_file = filename.contains("-debug"); let is_debug_file = filename.contains("-debug");
if flags.is_set(install_flags::DEBUG) != is_debug_file { if flags.is_set(install_flags::DEBUG) != is_debug_file {
io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?; io::copy(reader, &mut io::sink()).map_err(sevenz_rust2::Error::from)?;
@ -236,14 +279,31 @@ fn install_from_archive(
} }
} }
let extract_for_native_host_only = !should_install_by_flags
&& should_extract_pepper_for_native_host
&& (is_pp32 || is_pp64);
if extract_for_native_host_only {
form.update_progress_label(
"Extracting Pepper files required by modern browser support...",
true,
);
} else {
form.update_progress_label(install_entry.install_text, true); form.update_progress_label(install_entry.install_text, true);
}
let target_directory = if extract_for_native_host_only {
native_host_dir.clone()
} else {
install_entry.target_directory.clone()
};
// Ensure target directory exists. // Ensure target directory exists.
let _ = fs::create_dir_all(&install_entry.target_directory); let _ = fs::create_dir_all(&target_directory);
// Extract file: use just the file name (strip any path prefix). // Extract file: use just the file name (strip any path prefix).
let out_name = parts.last().unwrap_or(&filename); let out_name = parts.last().unwrap_or(&filename);
let out_path = install_entry.target_directory.join(out_name); let out_path = target_directory.join(out_name);
let mut buf = Vec::new(); let mut buf = Vec::new();
reader.read_to_end(&mut buf).map_err(sevenz_rust2::Error::from)?; reader.read_to_end(&mut buf).map_err(sevenz_rust2::Error::from)?;
@ -319,6 +379,11 @@ fn install_from_archive(
} }
} }
// Install native messaging host manifests for detected browsers.
if flags.is_set(install_flags::NATIVE_HOST) {
native_host::install_native_host(form)?;
}
Ok(()) Ok(())
} }

@ -1,4 +1,4 @@
//#![windows_subsystem = "windows"] #![windows_subsystem = "windows"]
mod install_flags; mod install_flags;
mod install_form; mod install_form;
@ -34,8 +34,8 @@ fn main() {
// Set window icon from the resource embedded by build.rs. // Set window icon from the resource embedded by build.rs.
clean_flash_ui::set_window_icon(&window); clean_flash_ui::set_window_icon(&window);
// Cap at ~60 fps. // Cap at ~24 fps.
window.set_target_fps(60); window.set_target_fps(24);
// Renderer operates at physical resolution; the form layout is scaled accordingly. // Renderer operates at physical resolution; the form layout is scaled accordingly.
let mut renderer = Renderer::new(phys_w, phys_h); let mut renderer = Renderer::new(phys_w, phys_h);

@ -21,7 +21,7 @@ including Clean Flash Player and older versions of Adobe Flash Player.";
const COMPLETE_TEXT: &str = "\nAll versions of Flash Player have been successfully uninstalled.\n\n\ const COMPLETE_TEXT: &str = "\nAll versions of Flash Player have been successfully uninstalled.\n\n\
If you ever change your mind, check out Clean Flash Player's website!"; If you ever change your mind, check out Clean Flash Player's website!";
const UNINSTALL_TICKS: i32 = 9; const UNINSTALL_TICKS: i32 = 10;
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
enum Panel { enum Panel {

Loading…
Cancel
Save