From f2e5f45876c3396bca4e2eeaaa26f1bf0f27c291 Mon Sep 17 00:00:00 2001 From: LDprg Date: Sun, 4 Aug 2024 18:05:10 +0000 Subject: [PATCH 1/3] clean and try to add rpm unpack --- scripts/install_quickemu.py | 110 --------------------------------- winapps-cli/Cargo.toml | 5 +- winapps-cli/src/main.rs | 52 +++------------- winapps/Cargo.toml | 23 ++++--- winapps/src/freerdp.rs | 117 ++++++++++++++++++++++++++++++++++-- winapps/src/lib.rs | 17 +----- winapps/src/quickemu.rs | 69 --------------------- 7 files changed, 146 insertions(+), 247 deletions(-) delete mode 100644 scripts/install_quickemu.py delete mode 100644 winapps/src/quickemu.rs diff --git a/scripts/install_quickemu.py b/scripts/install_quickemu.py deleted file mode 100644 index efaba950..00000000 --- a/scripts/install_quickemu.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python3 - -import platform -import os -import shutil -import sys - - -def _(c: str): - """Execute the command `c` and print it""" - print("> " + c) - os.system(c) - - -def clone_repo(): - if os.path.exists(os.path.expanduser("~/.local/share/quickemu")): - print("📦 quickemu is already installed. Updating...") - update_quickemu() - return - - print("📦 Cloning quickemu...") - - _("git clone --filter=blob:none https://github.com/quickemu-project/quickemu ~/.local/share/quickemu") - _("mkdir -p ~/.local/bin") - _("ln -s ~/.local/share/quickemu/quickemu ~/.local/bin/quickemu") - _("ln -s ~/.local/share/quickemu/macrecovery ~/.local/bin/macrecovery") - _("ln -s ~/.local/share/quickemu/quickget ~/.local/bin/quickget") - _("ln -s ~/.local/share/quickemu/windowskey ~/.local/bin/windowskey") - - print("Installation complete.") - print("⚠️ Make sure ~/.local/bin is in your PATH.") - - -def update_quickemu(): - print("📦 Updating quickemu...") - - _("cd ~/.local/share/quickemu") - _("git pull") - - print("Update complete.") - print("⚠️ Make sure ~/.local/bin is in your PATH.") - - -def install_fedora(): - print("📦 Installing dependencies...") - - _("sudo dnf install qemu bash coreutils edk2-tools grep jq lsb procps python3 genisoimage usbutils" - + " util-linux sed spice-gtk-tools swtpm wget xdg-user-dirs xrandr unzip socat -y") - - clone_repo() - - sys.exit(0) - - -def install_deb(): - print("📦 Installing dependencies...") - - _("sudo apt update") - _("sudo apt install qemu bash coreutils ovmf grep jq lsb-base procps python3 genisoimage usbutils" - + " util-linux sed spice-client-gtk libtss2-tcti-swtpm0 wget xdg-user-dirs zsync unzip socat -y") - - clone_repo() - - sys.exit(0) - - -def install_ubuntu(): - print("⚠️ Adding ppa...") - - _("sudo apt-add-repository ppa:flexiondotorg/quickemu") - _("sudo apt update") - _("sudo apt install quickemu -y") - - sys.exit(0) - - -if __name__ == "__main__": - print("⚠️ This script requires elevated privileges (sudo). You will be asked for your password.") - - os_release = platform.freedesktop_os_release() - - distro_id = os_release.get("ID_LIKE") - distro_id_like = os_release.get("ID") - - if not distro_id and not distro_id_like: - print("❌ Couldn't fetch distro, is os-release installed?") - - if distro_id == "ubuntu" \ - or distro_id_like == "ubuntu": - install_ubuntu() - elif distro_id == "debian" \ - or distro_id_like == "debian" \ - or shutil.which("apt"): - install_deb() - elif distro_id == "fedora" \ - or distro_id_like == "fedora" \ - or shutil.which("dnf"): - install_fedora() - else: - if distro_id: - print("❌ Unsupported distro: ", distro_id) - elif distro_id_like: - print("❌ Unsupported distro: ", distro_id_like) - else: - print("❌ Unsupported distro. Couldn't fetch data from os-release and couldn't find dnf or apt on PATH.") - - sys.exit(1) - - print("❌ Unsupported platform.") - sys.exit(1) diff --git a/winapps-cli/Cargo.toml b/winapps-cli/Cargo.toml index 6837cf7b..bcb76f97 100644 --- a/winapps-cli/Cargo.toml +++ b/winapps-cli/Cargo.toml @@ -7,5 +7,8 @@ default-run = "winapps-cli" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = "4.3.11" +clap = "4.3" +time = "0.3" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["time"] } winapps = { path = "../winapps" } diff --git a/winapps-cli/src/main.rs b/winapps-cli/src/main.rs index 3fb78ee0..7840ff90 100644 --- a/winapps-cli/src/main.rs +++ b/winapps-cli/src/main.rs @@ -1,6 +1,6 @@ use clap::{arg, Command}; +use tracing::info; use winapps::freerdp::freerdp_back::Freerdp; -use winapps::quickemu::{create_vm, kill_vm, start_vm}; use winapps::{unwrap_or_panic, RemoteClient}; fn cli() -> Command { @@ -16,19 +16,15 @@ fn cli() -> Command { .about("Connects to app on remote") .arg(arg!( "App to open")), ) - .subcommand( - Command::new("vm") - .about("Manage a windows 10 vm using quickemu") - .subcommand_required(true) - .arg_required_else_help(true) - .allow_external_subcommands(true) - .subcommand(Command::new("create").about("Create a windows 10 vm using quickget")) - .subcommand(Command::new("start").about("Start the vm")) - .subcommand(Command::new("kill").about("Kill the running VM")), - ) } fn main() { + tracing_subscriber::fmt() + // .with_timer(tracing_subscriber::fmt::time::uptime()) + .without_time() + .with_target(false) + .init(); + let cli = cli(); let matches = cli.clone().get_matches(); @@ -37,48 +33,20 @@ fn main() { match matches.subcommand() { Some(("check", _)) => { - println!("Checking remote connection"); + info!("Checking remote connection"); client.check_depends(config); } Some(("connect", _)) => { - println!("Connecting to remote"); + info!("Connecting to remote"); client.run_app(config, None); } Some(("run", sub_matches)) => { - println!("Connecting to app on remote"); + info!("Connecting to app on remote"); client.run_app(config, sub_matches.get_one::("APP")); } - - Some(("vm", command)) => { - match command.subcommand() { - Some(("create", _)) => { - println!("Creating windows 10 vm.."); - create_vm(config); - } - Some(("start", _)) => { - println!("Starting vm.."); - start_vm(config); - } - - Some(("kill", _)) => { - println!("Killing vm.."); - kill_vm(config); - } - - Some((_, _)) => { - unwrap_or_panic!( - cli.about("Command not found, try existing ones!") - .print_help(), - "Couldn't print help" - ); - } - _ => unreachable!(), - }; - } - Some((_, _)) => { unwrap_or_panic!( cli.about("Command not found, try existing ones!") diff --git a/winapps/Cargo.toml b/winapps/Cargo.toml index 8d6d0a55..7a0adf20 100644 --- a/winapps/Cargo.toml +++ b/winapps/Cargo.toml @@ -6,10 +6,19 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.75" -derive-new = "0.5.9" -home = "0.5.5" -serde = { version = "1.0.171", features = ["derive"] } -thiserror = "1.0.49" -toml = "0.8.2" -tracing = "0.1.37" +anyhow = "1.0" +decompress = "0.6.0" +derive-new = "0.5" +home = "0.5" +indicatif = { version="0.17", features = ["tokio"] } +regex = "1.10.6" +reqwest = { version = "0.12", features = ["stream"] } +serde = { version = "1.0", features = ["derive"] } +tempfile = "3.11.0" +thiserror = "1.0" +tokio = { version = "1.37", features = ["full"] } +tokio-stream = "0.1" +tokio-util = {version="0.7", features=["io"]} +toml = "0.8" +tracing = "0.1" +tracing-subscriber = "0.3" diff --git a/winapps/src/freerdp.rs b/winapps/src/freerdp.rs index b88936aa..6e4d3c33 100644 --- a/winapps/src/freerdp.rs +++ b/winapps/src/freerdp.rs @@ -1,14 +1,123 @@ pub mod freerdp_back { + use crate::{get_data_dir, unwrap_or_exit, Config, RemoteClient}; + use decompress::{decompressors, ExtractOptsBuilder}; + use indicatif::ProgressBar; + use regex::Regex; + use std::cmp::min; use std::process::{Command, Stdio}; + use tokio_stream::StreamExt; use tracing::{info, warn}; - use crate::{unwrap_or_exit, Config, RemoteClient}; - pub struct Freerdp {} + impl Freerdp { + fn get_freerdp() -> Command { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(Freerdp::install_freerdp()); + Command::new(get_data_dir().join("bin/xfreerdp")) + } + + // fn get_freerdp_dir() -> PathBuf { + // let path = get_data_dir().join("bin"); + + // if !path.exists() { + // let dir = path.clone(); + // info!( + // "Freerdp directory {:?} does not exist! Creating...", + // dir.to_str() + // ); + // fs::create_dir_all(dir).expect("Failed to create directory"); + // } + + // if !path.is_dir() { + // error!("Freerdp directory {:?} is not a directory", path).panic(); + // } + + // path + // } + + async fn install_freerdp() { + let freerdp_file = "freerdp-3.6.3-1.fc41.x86_64.rpm"; + let bar = ProgressBar::new(1); + + bar.set_style(indicatif::ProgressStyle::with_template( + "{spinner:.green} [{elapsed}] {wide_bar:.cyan/blue} {bytes}/{total_bytes} {bytes_per_sec} {msg} ({eta})", + ).unwrap().progress_chars("#>-")); + bar.set_message(format!("Starting {}", freerdp_file)); + + bar.tick(); + + let response = reqwest::get( + "https://kojipkgs.fedoraproject.org//packages/freerdp/3.6.3/1.fc41/x86_64/" + .to_owned() + + freerdp_file, + ) + .await + .unwrap(); + + let total_size = response.content_length().unwrap_or(0); + + bar.set_length(total_size); + bar.set_message(format!("Downloading {}", freerdp_file)); + + let mut downloaded: u64 = 0; + + let mut stream = response.bytes_stream().map(|result| { + result + .inspect(|result| { + let new = min(downloaded + (result.len() as u64), total_size); + downloaded = new; + bar.set_position(new); + }) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err)) + }); + + let mut tmp_file = tokio::fs::File::create(get_data_dir().join(freerdp_file)) + .await + .unwrap(); + + while let Some(item) = stream.next().await { + tokio::io::copy(&mut item.unwrap().as_ref(), &mut tmp_file) + .await + .unwrap(); + } + + // let mut decoder = + // async_compression::tokio::bufread::ZstdDecoder::new(StreamReader::new(stream)); + + // let mut target = tokio::fs::File::create(get_data_dir().join("bin1")) + // .await + // .unwrap(); + + // io::copy(&mut decoder, &mut target).await.unwrap(); + + // let file = tokio::fs::File::create(get_data_dir().join("bin1")) + // .await + // .unwrap(); + + let decompressor = + decompress::Decompress::build(vec![decompressors::zstd::Zstd::build(Some( + Regex::new(r".*").unwrap(), + ))]); + + let res = decompressor.decompress( + get_data_dir() + .join("freerdp-3.6.3-1.fc41.x86_64.zst") + .as_path(), + get_data_dir().join("bin").as_path(), + &ExtractOptsBuilder::default().build().unwrap(), + ); + + info!("{res:?}"); + } + } + impl RemoteClient for Freerdp { fn check_depends(&self, config: Config) { - let mut xfreerdp = Command::new("xfreerdp"); + let mut xfreerdp = Freerdp::get_freerdp(); xfreerdp.stdout(Stdio::null()); xfreerdp.stderr(Stdio::null()); xfreerdp.args(["-h"]); @@ -30,7 +139,7 @@ pub mod freerdp_back { } fn run_app(&self, config: Config, app: Option<&String>) { - let mut xfreerdp = Command::new("xfreerdp"); + let mut xfreerdp = Freerdp::get_freerdp(); xfreerdp.stdout(Stdio::null()); xfreerdp.stderr(Stdio::null()); match app { diff --git a/winapps/src/lib.rs b/winapps/src/lib.rs index 148f331e..1d2afda0 100644 --- a/winapps/src/lib.rs +++ b/winapps/src/lib.rs @@ -1,6 +1,5 @@ pub mod errors; pub mod freerdp; -pub mod quickemu; use crate::errors::WinappsError; use derive_new::new; @@ -27,16 +26,6 @@ pub struct Config { host: HostConfig, #[new(value = "RemoteConfig::new()")] rdp: RemoteConfig, - #[new(value = "VmConfig::new()")] - vm: VmConfig, -} - -#[derive(new, Debug, Deserialize, Serialize)] -pub struct VmConfig { - #[new(value = "\"windows-10\".to_string()")] - short_name: String, - #[new(value = "\"windows-10-22H2\".to_string()")] - name: String, } #[derive(new, Debug, Deserialize, Serialize)] @@ -49,11 +38,11 @@ pub struct HostConfig { pub struct RemoteConfig { #[new(value = "\"127.0.0.1\".to_string()")] host: String, - #[new(value = "\"WORKGROUP\".to_string()")] + #[new(value = "\"\".to_string()")] domain: String, - #[new(value = "\"Quickemu\".to_string()")] + #[new(value = "\"Docker\".to_string()")] username: String, - #[new(value = "\"quickemu\".to_string()")] + #[new(value = "\"\".to_string()")] password: String, } diff --git a/winapps/src/quickemu.rs b/winapps/src/quickemu.rs deleted file mode 100644 index d2cb54cd..00000000 --- a/winapps/src/quickemu.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::{get_data_dir, save_config, unwrap_or_exit, Config}; -use std::fs; -use std::process::Command; -use tracing::info; - -pub fn create_vm(mut config: Config) { - let data_dir = get_data_dir(); - - let output = unwrap_or_exit!( - Command::new("quickget") - .current_dir(data_dir) - .arg("windows") - .arg("10") - .output(), - "Failed to execute quickget: \n\ - Please make sure quickget is installed and in your PATH" - ); - - config.vm.name = "windows-10-22H2".to_string(); - config.vm.short_name = "windows-10".to_string(); - - unwrap_or_exit!(save_config(&config, None), "Failed to save config"); - - println!("{}", String::from_utf8_lossy(&output.stdout)); -} - -pub fn start_vm(config: Config) { - let data_dir = get_data_dir(); - - let command = unwrap_or_exit!( - Command::new("quickemu") - .current_dir(data_dir) - .args([ - "--ignore-msrs-always", - "--vm", - &format!("{}.conf", config.vm.name), - "--display", - "none", - ]) - .spawn(), - "Failed to execute quickemu: \n\ - Please make sure quickemu is installed and in your PATH" - ); - - let output = unwrap_or_exit!( - command.wait_with_output(), - "Failed to gather output from quickemu / stdout" - ); - - println!("{}", String::from_utf8_lossy(&output.stdout)); -} - -pub fn kill_vm(config: Config) { - let data_dir = get_data_dir(); - - let pid = unwrap_or_exit!( - fs::read_to_string( - data_dir.join(format!("{}/{}.pid", config.vm.short_name, config.vm.name)) - ), - "Failed to read PID file, is the VM running and the config correct?" - ); - - info!("Killing VM with PID {}", pid); - - unwrap_or_exit!( - Command::new("kill").arg(pid.trim()).spawn(), - "Failed to kill VM (execute kill)" - ); -} From da87a7b6536c9aa184cd6091fb6f17a90918d4f1 Mon Sep 17 00:00:00 2001 From: LDprg Date: Sun, 4 Aug 2024 18:43:34 +0000 Subject: [PATCH 2/3] install freerdp from rpm locally --- winapps/Cargo.toml | 5 ++- winapps/src/freerdp.rs | 80 ++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 52 deletions(-) diff --git a/winapps/Cargo.toml b/winapps/Cargo.toml index 7a0adf20..a712dbe7 100644 --- a/winapps/Cargo.toml +++ b/winapps/Cargo.toml @@ -7,14 +7,13 @@ edition = "2021" [dependencies] anyhow = "1.0" -decompress = "0.6.0" +sevenz-rust={version="0.2", features=["zstd"]} derive-new = "0.5" home = "0.5" indicatif = { version="0.17", features = ["tokio"] } -regex = "1.10.6" reqwest = { version = "0.12", features = ["stream"] } serde = { version = "1.0", features = ["derive"] } -tempfile = "3.11.0" +tempfile = "3.11" thiserror = "1.0" tokio = { version = "1.37", features = ["full"] } tokio-stream = "0.1" diff --git a/winapps/src/freerdp.rs b/winapps/src/freerdp.rs index 6e4d3c33..c64efab1 100644 --- a/winapps/src/freerdp.rs +++ b/winapps/src/freerdp.rs @@ -1,9 +1,8 @@ pub mod freerdp_back { use crate::{get_data_dir, unwrap_or_exit, Config, RemoteClient}; - use decompress::{decompressors, ExtractOptsBuilder}; use indicatif::ProgressBar; - use regex::Regex; use std::cmp::min; + use std::fs::File; use std::process::{Command, Stdio}; use tokio_stream::StreamExt; use tracing::{info, warn}; @@ -17,30 +16,16 @@ pub mod freerdp_back { .build() .unwrap() .block_on(Freerdp::install_freerdp()); - Command::new(get_data_dir().join("bin/xfreerdp")) + Command::new(get_data_dir().join("usr/bin/xfreerdp")) } - // fn get_freerdp_dir() -> PathBuf { - // let path = get_data_dir().join("bin"); - - // if !path.exists() { - // let dir = path.clone(); - // info!( - // "Freerdp directory {:?} does not exist! Creating...", - // dir.to_str() - // ); - // fs::create_dir_all(dir).expect("Failed to create directory"); - // } - - // if !path.is_dir() { - // error!("Freerdp directory {:?} is not a directory", path).panic(); - // } - - // path - // } - async fn install_freerdp() { + if get_data_dir().join("usr/bin/xfreerdp").exists() { + return; + } + let freerdp_file = "freerdp-3.6.3-1.fc41.x86_64.rpm"; + let bar = ProgressBar::new(1); bar.set_style(indicatif::ProgressStyle::with_template( @@ -51,7 +36,7 @@ pub mod freerdp_back { bar.tick(); let response = reqwest::get( - "https://kojipkgs.fedoraproject.org//packages/freerdp/3.6.3/1.fc41/x86_64/" + "https://kojipkgs.fedoraproject.org/packages/freerdp/3.6.3/1.fc41/x86_64/" .to_owned() + freerdp_file, ) @@ -75,43 +60,40 @@ pub mod freerdp_back { .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err)) }); - let mut tmp_file = tokio::fs::File::create(get_data_dir().join(freerdp_file)) + let mut file = tokio::fs::File::create(get_data_dir().join(freerdp_file)) .await .unwrap(); while let Some(item) = stream.next().await { - tokio::io::copy(&mut item.unwrap().as_ref(), &mut tmp_file) + tokio::io::copy(&mut item.unwrap().as_ref(), &mut file) .await .unwrap(); } - // let mut decoder = - // async_compression::tokio::bufread::ZstdDecoder::new(StreamReader::new(stream)); - - // let mut target = tokio::fs::File::create(get_data_dir().join("bin1")) - // .await - // .unwrap(); - - // io::copy(&mut decoder, &mut target).await.unwrap(); - - // let file = tokio::fs::File::create(get_data_dir().join("bin1")) - // .await - // .unwrap(); + let mut rpm2cpio = Command::new("rpm2cpio"); + rpm2cpio.stdin(Stdio::from( + File::open(get_data_dir().join(freerdp_file)).unwrap(), + )); + rpm2cpio.stdout(Stdio::piped()); + rpm2cpio.stderr(Stdio::null()); + rpm2cpio.current_dir(get_data_dir()); + + let rpm2cpio = unwrap_or_exit!( + rpm2cpio.spawn(), + "rpm2cpio execution failed! Check if rpm2cpio (rpm) is installed!", + ); - let decompressor = - decompress::Decompress::build(vec![decompressors::zstd::Zstd::build(Some( - Regex::new(r".*").unwrap(), - ))]); + let mut cpio = Command::new("cpio"); + cpio.stdin(Stdio::from(rpm2cpio.stdout.unwrap())); + cpio.stdout(Stdio::null()); + cpio.stderr(Stdio::null()); + cpio.current_dir(get_data_dir()); + cpio.arg("-idmv"); - let res = decompressor.decompress( - get_data_dir() - .join("freerdp-3.6.3-1.fc41.x86_64.zst") - .as_path(), - get_data_dir().join("bin").as_path(), - &ExtractOptsBuilder::default().build().unwrap(), + unwrap_or_exit!( + cpio.spawn(), + "cpio execution failed! Check if cpio is installed!", ); - - info!("{res:?}"); } } From a2c02a840a959989e95755a1d14929b6381d0610 Mon Sep 17 00:00:00 2001 From: LDprg Date: Sun, 4 Aug 2024 18:45:37 +0000 Subject: [PATCH 3/3] fix error log --- winapps/src/freerdp.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winapps/src/freerdp.rs b/winapps/src/freerdp.rs index c64efab1..4865f684 100644 --- a/winapps/src/freerdp.rs +++ b/winapps/src/freerdp.rs @@ -106,7 +106,8 @@ pub mod freerdp_back { unwrap_or_exit!( xfreerdp.spawn(), - "Freerdp execution failed! It needs to be installed!", + "Freerdp execution failed! Try to delete {}, to force a reinstall.", + get_data_dir().join("usr").display(), ); info!("Freerdp found!");