diff --git a/src/core_main.rs b/src/core_main.rs index bda6580ee..4fc4c2080 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -248,9 +248,6 @@ pub fn core_main() -> Option> { crate::plugin::install_plugin_with_url(&args[1], &args[2]); } return None; - } else if args[0] == "--plugin-uninstall" { - // Do nothing - return None; } } } diff --git a/src/platform/linux.rs b/src/platform/linux.rs index c80ab907a..ca35fc32b 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -9,10 +9,10 @@ use hbb_common::{ regex::{Captures, Regex}, }; use std::{ - string::String, cell::RefCell, path::{Path, PathBuf}, process::{Child, Command}, + string::String, sync::{ atomic::{AtomicBool, Ordering}, Arc, @@ -453,9 +453,7 @@ pub fn get_active_username() -> String { pub fn get_user_home_by_name(username: &str) -> Option { return match get_user_by_name(username) { - None => { - None - } + None => None, Some(user) => { let home = user.home_dir(); if Path::is_dir(home) { @@ -464,7 +462,7 @@ pub fn get_user_home_by_name(username: &str) -> Option { None } } - } + }; } pub fn get_active_user_home() -> Option { @@ -835,12 +833,7 @@ mod desktop { } fn get_display(&mut self) { - let display_envs = vec![ - GNOME_SESSION_BINARY, - XFCE4_PANEL, - SDDM_GREETER, - PLASMA_X11, - ]; + let display_envs = vec![GNOME_SESSION_BINARY, XFCE4_PANEL, SDDM_GREETER, PLASMA_X11]; for diplay_env in display_envs { self.display = get_env_tries("DISPLAY", &self.uid, diplay_env, 10); if !self.display.is_empty() { @@ -873,8 +866,8 @@ mod desktop { auth_found = true; } else if auth_found { if std::path::Path::new(v).is_absolute() - && std::path::Path::new(v).exists() { - + && std::path::Path::new(v).exists() + { self.xauth = v.to_string(); } else { if let Some(pid) = line.split_whitespace().nth(1) { @@ -903,12 +896,7 @@ mod desktop { fn get_xauth(&mut self) { // try by direct access to window manager process by name - let display_envs = vec![ - GNOME_SESSION_BINARY, - XFCE4_PANEL, - SDDM_GREETER, - PLASMA_X11, - ]; + let display_envs = vec![GNOME_SESSION_BINARY, XFCE4_PANEL, SDDM_GREETER, PLASMA_X11]; for diplay_env in display_envs { self.xauth = get_env_tries("XAUTHORITY", &self.uid, diplay_env, 10); if !self.xauth.is_empty() { @@ -928,7 +916,7 @@ mod desktop { gdm } else { let username = &self.username; - match get_user_home_by_name(username) { + match get_user_home_by_name(username) { None => { if username == "root" { format!("/{}/.Xauthority", username) @@ -942,7 +930,10 @@ mod desktop { } } Some(home) => { - format!("{}/.Xauthority", home.as_path().to_string_lossy().to_string()) + format!( + "{}/.Xauthority", + home.as_path().to_string_lossy().to_string() + ) } } }; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index e382b0b13..454058b5a 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -54,6 +54,27 @@ pub fn get_active_username() -> String { #[cfg(target_os = "android")] pub const PA_SAMPLE_RATE: u32 = 48000; +#[cfg(any(target_os = "linux", target_os = "macos"))] +pub fn run_as_root(arg: Vec<&str>) -> ResultType> { + let cmd = std::env::current_exe()?; + match cmd.to_str() { + Some(cmd) => { + let mut args = vec![cmd]; + args.append(&mut arg.clone()); + // -E required for opensuse + #[cfg(target_os = "linux")] + if is_opensuse() { + args.insert(0, "-E"); + } + let task = Command::new("sudo").args(args).spawn()?; + Ok(Some(task)) + } + None => { + bail!("Failed to get current exe as str"); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/plugin/desc.rs b/src/plugin/desc.rs index 511d187a4..04c85d6b0 100644 --- a/src/plugin/desc.rs +++ b/src/plugin/desc.rs @@ -58,6 +58,8 @@ pub struct Meta { pub name: String, pub version: String, pub description: String, + #[serde(default)] + pub platforms: String, pub author: String, pub home: String, pub license: String, diff --git a/src/plugin/manager.rs b/src/plugin/manager.rs index 9480445bf..2aaddd55f 100644 --- a/src/plugin/manager.rs +++ b/src/plugin/manager.rs @@ -19,6 +19,13 @@ const MSG_TO_UI_PLUGIN_MANAGER_UNINSTALL: &str = "plugin_uninstall"; const IPC_PLUGIN_POSTFIX: &str = "_plugin"; +#[cfg(target_os = "windows")] +const PLUGIN_PLATFORM: &str = "Windows"; +#[cfg(target_os = "linux")] +const PLUGIN_PLATFORM: &str = "Linux"; +#[cfg(target_os = "macos")] +const PLUGIN_PLATFORM: &str = "MacOS"; + lazy_static::lazy_static! { static ref PLUGIN_INFO: Arc>> = Arc::new(Mutex::new(HashMap::new())); } @@ -73,6 +80,9 @@ fn get_source_plugins() -> HashMap { match toml::from_str::(&text) { Ok(manager_meta) => { for meta in manager_meta.plugins.iter() { + if !meta.platforms.contains(PLUGIN_PLATFORM) { + continue; + } plugins.insert( meta.id.clone(), PluginInfo { @@ -147,33 +157,59 @@ pub fn load_plugin_list() { pub fn install_plugin(id: &str) -> ResultType<()> { match PLUGIN_INFO.lock().unwrap().get(id) { Some(plugin) => { + let mut same_plugin_exists = false; + if let Some(version) = super::plugins::get_version(id) { + if version == plugin.meta.version { + same_plugin_exists = true; + } + } + + let plugin_url = format!( + "{}/plugins/{}/{}/{}_{}.zip", + plugin.source.url, + plugin.meta.id, + PLUGIN_PLATFORM, + plugin.meta.id, + plugin.meta.version + ); + + let allowed_install; #[cfg(windows)] { - let mut same_plugin_exists = false; - if let Some(version) = super::plugins::get_version(id) { - if version == plugin.meta.version { - same_plugin_exists = true; - } - } - // to-do: Support args with space in quotes. 'arg 1' and "arg 2" - let plugin_url = format!( - "{}/plugins/{}/{}_{}.zip", - plugin.source.url, plugin.meta.id, plugin.meta.id, plugin.meta.version - ); let args = if same_plugin_exists { format!("--plugin-install {}", id) } else { format!("--plugin-install {} {}", id, plugin_url) }; - let allowed = crate::platform::elevate(&args)?; - - if allowed && same_plugin_exists { - super::ipc::load_plugin(id)?; - super::plugins::load_plugin(id)?; - super::plugins::mark_uninstalled(id, false); - push_install_event(id, "finished"); + allowed_install = crate::platform::elevate(&args)?; + } + #[cfg(target_os = "linux")] + { + let mut args = vec!["--plugin-install", id]; + if !same_plugin_exists { + args.push(&plugin_url); } + allowed_install = match crate::platform::run_as_root(&args) { + Ok(child) => match child.wait() { + Ok(0) => true, + Ok(code) => { + log::error!("Failed to wait install process, process code: {}", code); + true + } + Err(e) => { + log::error!("Failed to wait install process, error: {}", e); + false + } + }, + } + } + + if allowed_install && same_plugin_exists { + super::ipc::load_plugin(id)?; + super::plugins::load_plugin(id)?; + super::plugins::mark_uninstalled(id, false); + push_install_event(id, "finished"); } Ok(()) } @@ -220,7 +256,8 @@ pub(super) fn remove_plugins() -> ResultType<()> { pub fn uninstall_plugin(id: &str, called_by_ui: bool) { if called_by_ui { - match crate::platform::elevate(&format!("--plugin-uninstall {}", id)) { + #[cfg(target_os = "windows")] + match crate::platform::check_super_user_permission() { Ok(true) => { if let Err(e) = super::ipc::uninstall_plugin(id) { log::error!("Failed to uninstall plugin '{}': {}", id, e); @@ -236,7 +273,11 @@ pub fn uninstall_plugin(id: &str, called_by_ui: bool) { return; } Err(e) => { - log::error!("Failed to uninstall plugin '{}': {}", id, e); + log::error!( + "Failed to uninstall plugin '{}', check permission error: {}", + id, + e + ); push_uninstall_event(id, "failed"); return; } diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 7ec690c59..9a72d2aed 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -100,10 +100,27 @@ pub fn init() { } } +#[inline] +#[cfg(target_os = "windows")] +fn get_share_dir() -> ResultType { + Ok(PathBuf::from(env::var("ProgramData")?)) +} + +#[inline] +#[cfg(target_os = "linux")] +fn get_share_dir() -> ResultType { + Ok(PathBuf::from("/usr/share")) +} + +#[inline] +#[cfg(target_os = "macos")] +fn get_share_dir() -> ResultType { + Ok(PathBuf::from("/Library/Application Support")) +} + #[inline] fn get_plugins_dir() -> ResultType { - // to-do: linux and macos - Ok(PathBuf::from(env::var("ProgramData")?) + Ok(get_share_dir()? .join("RustDesk") .join(PLUGIN_SOURCE_LOCAL_DIR)) }