From 133a58dc2f77bd0e510fab955e61df61edf14010 Mon Sep 17 00:00:00 2001 From: tiziodcaio Date: Fri, 26 Jan 2024 22:11:22 +0100 Subject: [PATCH] Experimental replacement of 7zip with rust static-linked library Not tested yet --- native/Cargo.lock | 143 ++++++++++++++++++++++++ native/Cargo.toml | 1 + native/src/components/_7zip.rs | 184 ------------------------------- native/src/components/mod.rs | 3 - native/src/components/runtime.rs | 13 ++- native/src/connector/process.rs | 40 +------ native/src/connector/response.rs | 7 -- native/src/console/runtime.rs | 15 --- 8 files changed, 157 insertions(+), 249 deletions(-) delete mode 100644 native/src/components/_7zip.rs diff --git a/native/Cargo.lock b/native/Cargo.lock index 9ba489a6..21d85b99 100644 --- a/native/Cargo.lock +++ b/native/Cargo.lock @@ -185,6 +185,21 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit_field" version = "0.10.2" @@ -203,6 +218,15 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "brotli" version = "3.4.0" @@ -406,6 +430,30 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.3.2" @@ -446,6 +494,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "csscolorparser" version = "0.6.2" @@ -517,6 +575,16 @@ dependencies = [ "serde", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "directories" version = "5.0.1" @@ -633,6 +701,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "filetime_creation" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d273b12293b73b44ab8a525e161f74ebe2f38dd50c33ce7f538a4ccf9077383" +dependencies = [ + "cfg-if", + "filetime", + "windows-sys 0.52.0", +] + [[package]] name = "firefoxpwa" version = "0.0.0" @@ -665,6 +744,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "sevenz-rust", "simplelog", "smart-default", "tar", @@ -819,6 +899,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1184,6 +1274,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lzma-rust" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f798132166cc040cb70dbab4ccbb89643a6966a4ac33f0b312e76a8238673a5" +dependencies = [ + "byteorder", +] + [[package]] name = "memchr" version = "2.7.1" @@ -1268,6 +1367,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nt-time" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f44d3e957730fcdc4dff6f97c1185f175ee27e6dd92000c0487d70049a1b81a" +dependencies = [ + "chrono", + "time", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1946,6 +2055,34 @@ dependencies = [ "syn", ] +[[package]] +name = "sevenz-rust" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233a1e86d0c5f6c8c29808a563f1e504ca0497368251ce59dc013807f43a4659" +dependencies = [ + "bit-set", + "byteorder", + "crc", + "filetime_creation", + "js-sys", + "lzma-rust", + "nt-time", + "sha2", + "wasm-bindgen", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -2337,6 +2474,12 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "ulid" version = "1.1.0" diff --git a/native/Cargo.toml b/native/Cargo.toml index 0f5f440e..85ee8fbe 100644 --- a/native/Cargo.toml +++ b/native/Cargo.toml @@ -52,6 +52,7 @@ urlencoding = "2.1.3" web_app_manifest = { git = "https://github.com/filips123/WebAppManifestRS", branch = "main" } [target.'cfg(target_os = "windows")'.dependencies] +sevenz-rust = {version= "0.5.4", features = []} winreg = "0.50.0" sanitize-filename = "0.5.0" phf = { version = "0.11.2", features = ["macros"], optional = true } diff --git a/native/src/components/_7zip.rs b/native/src/components/_7zip.rs deleted file mode 100644 index 657c0094..00000000 --- a/native/src/components/_7zip.rs +++ /dev/null @@ -1,184 +0,0 @@ -use std::ffi::OsStr; -use std::fs::remove_file; -use std::os::windows::process::ExitStatusExt; -use std::path::PathBuf; -use std::process::{Command, ExitStatus}; - -use anyhow::{bail, Context, Result}; -use cfg_if::cfg_if; -use const_format::formatcp; -use log::{info, warn}; -use tempfile::Builder; -use windows::core::{w, HSTRING, PCWSTR}; -use windows::Win32::System::Com::{ - CoInitializeEx, - COINIT_APARTMENTTHREADED, - COINIT_DISABLE_OLE1DDE, -}; -use windows::Win32::System::Threading::{GetExitCodeProcess, WaitForSingleObject, INFINITE}; -use windows::Win32::UI::Shell::{ - ShellExecuteExW, - SEE_MASK_NOASYNC, - SEE_MASK_NOCLOSEPROCESS, - SHELLEXECUTEINFOW, -}; -use winreg::enums::HKEY_LOCAL_MACHINE; -use winreg::RegKey; - -#[inline] -const fn get_download_url() -> &'static str { - #[allow(unused_imports)] - use const_format::formatcp; - - #[allow(dead_code)] - const VERSION: &str = "2301"; - - cfg_if! { - if #[cfg(target_arch = "x86")] { - const ARCHITECTURE: &str = ""; - } else if #[cfg(target_arch = "x86_64")] { - const ARCHITECTURE: &str = "-x64"; - } else if #[cfg(target_arch = "aarch64")] { - const ARCHITECTURE: &str = "-arm64"; - } else { - panic!("Cannot install 7-Zip: Unsupported architecture!"); - } - } - - formatcp!("https://7-zip.org/a/7z{VERSION}{ARCHITECTURE}.exe") -} - -#[inline] -fn run_as_admin>(cmd: S) -> std::io::Result { - unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)? }; - - let mut code = 1; - let file = HSTRING::from(cmd.as_ref()); - - let mut sei = SHELLEXECUTEINFOW { - cbSize: std::mem::size_of::() as u32, - fMask: SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS, - lpVerb: w!("runas"), - lpFile: PCWSTR(file.as_ptr()), - nShow: 1, - ..Default::default() - }; - - unsafe { - ShellExecuteExW(&mut sei)?; - let process = { sei.hProcess }; - - if process.is_invalid() { - return Err(std::io::Error::last_os_error()); - }; - - WaitForSingleObject(process, INFINITE); - GetExitCodeProcess(process, &mut code)?; - }; - - Ok(ExitStatus::from_raw(code)) -} - -#[non_exhaustive] -#[derive(Debug, Eq, PartialEq, Clone)] -pub struct _7Zip { - pub version: Option, - executable: Option, -} - -impl _7Zip { - pub fn new() -> Result { - match Self::new_from_registry().context("Failed to search 7-Zip in registry")? { - registry if registry.version.is_some() => Ok(registry), - _ => Self::new_from_path().context("Failed to search 7-Zip in PATH variable"), - } - } - - fn new_from_registry() -> Result { - let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let subkey = hklm.open_subkey(r"Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip"); - - let version; - let executable; - - match subkey { - Ok(subkey) => { - let display_version: String = subkey.get_value("DisplayVersion")?; - let install_location: String = subkey.get_value("InstallLocation")?; - - version = Some(display_version); - executable = Some(PathBuf::from(install_location).join("7z.exe")); - } - Err(_) => { - version = None; - executable = None; - } - } - - Ok(Self { version, executable }) - } - - fn new_from_path() -> Result { - let exe = std::env::var_os("PATH").and_then(|paths| { - std::env::split_paths(&paths) - .filter_map(|directory| { - let executable = directory.join("7z.exe"); - match executable.is_file() { - true => Some(executable), - false => None, - } - }) - .next() - }); - - match exe { - Some(exe) => Ok(Self { version: Some("0.0.0".into()), executable: Some(exe) }), - None => Ok(Self { version: None, executable: None }), - } - } - - pub fn install(self) -> Result<()> { - const TEMP_FILE_ERROR: &str = "Failed to create a temporary file"; - const DOWNLOAD_ERROR: &str = "Failed to download the 7-Zip installer"; - const EXEC_ERROR: &str = "Failed to execute the 7-Zip installer"; - const CLEANUP_ERROR: &str = "Failed to clean up the 7-Zip installer"; - - warn!("This will install 7-Zip, made by Igor Pavlov, licensed under the GNU LGPL license and others"); - warn!("This project is not affiliated with the 7-Zip project or its developers in any way"); - warn!("Check the 7-zip website for more details: https://7-zip.org/"); - - let mut installer = Builder::new() - .prefix("firefoxpwa-7zip-") - .suffix(".exe") - .tempfile() - .context(TEMP_FILE_ERROR)?; - - info!("Downloading the 7-Zip installer"); - let mut response = reqwest::blocking::get(get_download_url()).context(DOWNLOAD_ERROR)?; - (response.copy_to(&mut installer.as_file_mut())).context(DOWNLOAD_ERROR)?; - let (_, path) = installer.keep().context(DOWNLOAD_ERROR)?; - - info!("Executing the 7-Zip installer"); - warn!("Please follow the installer to install 7-Zip"); - warn!("You might need to accept the User Account Control prompt"); - - if !run_as_admin(&path).context(EXEC_ERROR)?.success() { - bail!(EXEC_ERROR) - } - - remove_file(path).context(CLEANUP_ERROR)?; - - info!("7-Zip installed!"); - Ok(()) - } - - #[inline] - pub fn run(&self, args: Vec<&str>) -> Result { - let executable = match &self.executable { - Some(executable) => executable, - None => bail!("7-Zip is currently not installed"), - }; - - Ok(Command::new(executable).args(args).spawn()?.wait()?) - } -} diff --git a/native/src/components/mod.rs b/native/src/components/mod.rs index ddce20b2..0ba563fd 100644 --- a/native/src/components/mod.rs +++ b/native/src/components/mod.rs @@ -1,6 +1,3 @@ -#[cfg(platform_windows)] -pub mod _7zip; - pub mod profile; pub mod runtime; pub mod site; diff --git a/native/src/components/runtime.rs b/native/src/components/runtime.rs index f6f37541..dee1391c 100644 --- a/native/src/components/runtime.rs +++ b/native/src/components/runtime.rs @@ -223,12 +223,15 @@ impl Runtime { cfg_if! { if #[cfg(platform_windows)] { use anyhow::bail; - use crate::components::_7zip::_7Zip; - let _7zip = _7Zip::new()?; - let success = _7zip.run(vec!["x", &archive, &format!("-o{}", &extracted)]).context(EXTRACT_ERROR)?.success(); - if !success { bail!(EXTRACT_ERROR) } - source.push("core"); + match sevenz_rust::decompress_file(&archive,&extracted) { + Ok(_) => { + source.push("core"); + } + Err(_) => { + bail!(EXTRACT_ERROR); + } + } } else if #[cfg(platform_linux)] { use std::fs::File; use bzip2::read::BzDecoder; diff --git a/native/src/connector/process.rs b/native/src/connector/process.rs index c09df418..74f71769 100644 --- a/native/src/connector/process.rs +++ b/native/src/connector/process.rs @@ -4,36 +4,16 @@ use log::{info, warn}; use crate::components::runtime::Runtime; use crate::connector::request::{ - CreateProfile, - GetConfig, - GetProfileList, - GetSiteList, - GetSystemVersions, - InstallRuntime, - InstallSite, - LaunchSite, - PatchAllProfiles, - RegisterProtocolHandler, - RemoveProfile, - SetConfig, - UninstallRuntime, - UninstallSite, - UnregisterProtocolHandler, - UpdateAllSites, - UpdateProfile, + CreateProfile, GetConfig, GetProfileList, GetSiteList, GetSystemVersions, InstallRuntime, + InstallSite, LaunchSite, PatchAllProfiles, RegisterProtocolHandler, RemoveProfile, SetConfig, + UninstallRuntime, UninstallSite, UnregisterProtocolHandler, UpdateAllSites, UpdateProfile, UpdateSite, }; use crate::connector::response::ConnectorResponse; use crate::connector::Connection; use crate::console::app::{ - ProfileCreateCommand, - ProfileRemoveCommand, - ProfileUpdateCommand, - RuntimeInstallCommand, - RuntimeUninstallCommand, - SiteInstallCommand, - SiteLaunchCommand, - SiteUninstallCommand, + ProfileCreateCommand, ProfileRemoveCommand, ProfileUpdateCommand, RuntimeInstallCommand, + RuntimeUninstallCommand, SiteInstallCommand, SiteLaunchCommand, SiteUninstallCommand, SiteUpdateCommand, }; use crate::console::Run; @@ -51,16 +31,6 @@ impl Process for GetSystemVersions { Ok(ConnectorResponse::SystemVersions { firefoxpwa: Some(env!("CARGO_PKG_VERSION").into()), firefox: Runtime::new(connection.dirs)?.version, - _7zip: { - cfg_if! { - if #[cfg(platform_windows)] { - use crate::components::_7zip::_7Zip; - _7Zip::new()?.version - } else { - None - } - } - }, }) } } diff --git a/native/src/connector/response.rs b/native/src/connector/response.rs index 0309b4a2..a9f67b31 100644 --- a/native/src/connector/response.rs +++ b/native/src/connector/response.rs @@ -23,13 +23,6 @@ pub enum ConnectorResponse { /// /// Only set if the runtime is installed. firefox: Option, - - /// Version of the 7-Zip program. - /// - /// Only set on Windows, and if 7-Zip is installed. - /// May also be `0.0.0` if 7-Zip was located through - /// the `PATH` environment variable. - _7zip: Option, }, /// Config of the native program. diff --git a/native/src/console/runtime.rs b/native/src/console/runtime.rs index ccbe4ed8..34c9eb77 100644 --- a/native/src/console/runtime.rs +++ b/native/src/console/runtime.rs @@ -1,5 +1,4 @@ use anyhow::{Context, Result}; -use cfg_if::cfg_if; use crate::components::runtime::Runtime; use crate::console::app::{RuntimeInstallCommand, RuntimePatchCommand, RuntimeUninstallCommand}; @@ -9,20 +8,6 @@ use crate::directories::ProjectDirs; impl Run for RuntimeInstallCommand { #[cfg(not(feature = "immutable-runtime"))] fn run(&self) -> Result<()> { - cfg_if! { - if #[cfg(platform_windows)] { - use log::warn; - use crate::components::_7zip::_7Zip; - - let _7zip = _7Zip::new()?; - if _7zip.version.is_none() { - warn!("7-Zip is currently not installed and will be installed automatically"); - warn!("You can remove it manually after the runtime is installed"); - _7zip.install().context("Failed to install 7-Zip")?; - } - } - } - let dirs = ProjectDirs::new()?; let runtime = Runtime::new(&dirs)?; runtime.install().context("Failed to install runtime")?;