From 2e03ca19f6afe9bb705e041af3b97e2ddb398ba7 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Wed, 12 Jan 2022 21:40:02 +0800 Subject: [PATCH 01/13] temp commit --- Cargo.lock | 77 +++++++++++++++++ Cargo.toml | 1 + libs/hbb_common/Cargo.toml | 3 + libs/hbb_common/src/config.rs | 154 +++++++++++++++++++++++----------- src/ipc.rs | 51 ++++++----- src/lib.rs | 2 +- src/main.rs | 86 ++++++++++--------- src/platform/macos.rs | 7 ++ src/server.rs | 98 +++++++++++++++++++--- 9 files changed, 358 insertions(+), 121 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ea2e7c9b..9c3f27000 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,6 +1115,31 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + +[[package]] +name = "fsevent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" +dependencies = [ + "bitflags", + "fsevent-sys", +] + +[[package]] +name = "fsevent-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +dependencies = [ + "libc", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1623,6 +1648,7 @@ dependencies = [ "dirs-next", "env_logger 0.9.0", "filetime", + "fs_extra", "futures", "futures-util", "lazy_static", @@ -1698,6 +1724,26 @@ dependencies = [ "tiff", ] +[[package]] +name = "inotify" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "instant" version = "0.1.12" @@ -2060,6 +2106,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio 0.6.23", + "slab", +] + [[package]] name = "mio-named-pipes" version = "0.1.7" @@ -2224,6 +2282,24 @@ dependencies = [ "version_check", ] +[[package]] +name = "notify" +version = "4.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +dependencies = [ + "bitflags", + "filetime", + "fsevent", + "fsevent-sys", + "inotify", + "libc", + "mio 0.6.23", + "mio-extras", + "walkdir", + "winapi 0.3.9", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -3153,6 +3229,7 @@ dependencies = [ "mac_address", "machine-uid", "magnum-opus", + "notify", "objc", "parity-tokio-ipc", "psutil", diff --git a/Cargo.toml b/Cargo.toml index 6a9325e25..9a13bedaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ cocoa = "0.24" dispatch = "0.2" core-foundation = "0.9" core-graphics = "0.22" +notify = "4.0.17" [target.'cfg(target_os = "linux")'.dependencies] libpulse-simple-binding = "2.24" diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index d1868f5b5..485e91ba0 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -43,6 +43,9 @@ protobuf-codegen-pure = "3.0.0-alpha.2" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winuser"] } +[target.'cfg(target_os = "macos")'.dependencies] +fs_extra = "1.2.0" + [dev-dependencies] toml = "0.5" serde_json = "1.0" diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index d248f0c28..e9df2f15c 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -11,6 +11,7 @@ use std::{ sync::{Arc, Mutex, RwLock}, time::SystemTime, }; +use std::borrow::Borrow; pub const APP_NAME: &str = "RustDesk"; pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; @@ -69,7 +70,8 @@ pub struct Config { #[serde(default)] salt: String, #[serde(default)] - key_pair: (Vec, Vec), // sk, pk + key_pair: (Vec, Vec), + // sk, pk #[serde(default)] key_confirmed: bool, #[serde(default)] @@ -90,7 +92,8 @@ pub struct Socks5Server { #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct Config2 { #[serde(default)] - remote_id: String, // latest used one + remote_id: String, + // latest used one #[serde(default)] size: Size, #[serde(default)] @@ -119,7 +122,8 @@ pub struct PeerConfig { #[serde(default)] pub size_pf: Size, #[serde(default)] - pub view_style: String, // original (default), scale + pub view_style: String, + // original (default), scale #[serde(default)] pub image_quality: String, #[serde(default)] @@ -159,28 +163,28 @@ pub struct PeerInfoSerde { fn patch(path: PathBuf) -> PathBuf { if let Some(_tmp) = path.to_str() { #[cfg(windows)] - return _tmp + return _tmp .replace( "system32\\config\\systemprofile", "ServiceProfiles\\LocalService", ) .into(); #[cfg(target_os = "macos")] - return _tmp.replace("Application Support", "Preferences").into(); + return _tmp.replace("Application Support", "Preferences").into(); #[cfg(target_os = "linux")] - { - if _tmp == "/root" { - if let Ok(output) = std::process::Command::new("whoami").output() { - let user = String::from_utf8_lossy(&output.stdout) - .to_string() - .trim() - .to_owned(); - if user != "root" { - return format!("/home/{}", user).into(); + { + if _tmp == "/root" { + if let Ok(output) = std::process::Command::new("whoami").output() { + let user = String::from_utf8_lossy(&output.stdout) + .to_string() + .trim() + .to_owned(); + if user != "root" { + return format!("/home/{}", user).into(); + } } } } - } } path } @@ -190,6 +194,11 @@ impl Config2 { Config::load_::("2") } + fn reload(&mut self) { + let new_config = Config2::load(); + *self = new_config; + } + fn store(&self) { Config::store_(self, "2"); } @@ -229,6 +238,11 @@ impl Config { Config::store_(self, ""); } + fn reload(&mut self) { + let new_config = Config::load(); + *self = new_config; + } + pub fn file() -> PathBuf { Self::file_("") } @@ -262,7 +276,7 @@ impl Config { pub fn get_home() -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - return Self::path(""); + return Self::path(""); if let Some(path) = dirs_next::home_dir() { patch(path) } else if let Ok(path) = std::env::current_dir() { @@ -272,17 +286,17 @@ impl Config { } } - fn path>(p: P) -> PathBuf { + pub fn path>(p: P) -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - { - let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); - path.push(p); - return path; - } + { + let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); + path.push(p); + return path; + } #[cfg(not(target_os = "macos"))] - let org = ""; + let org = ""; #[cfg(target_os = "macos")] - let org = ORG; + let org = ORG; // /var/root for root if let Some(project) = ProjectDirs::from("", org, APP_NAME) { let mut path = patch(project.config_dir().to_path_buf()); @@ -295,19 +309,19 @@ impl Config { #[allow(unreachable_code)] pub fn log_path() -> PathBuf { #[cfg(target_os = "macos")] - { - if let Some(path) = dirs_next::home_dir().as_mut() { - path.push(format!("Library/Logs/{}", APP_NAME)); - return path.clone(); + { + if let Some(path) = dirs_next::home_dir().as_mut() { + path.push(format!("Library/Logs/{}", APP_NAME)); + return path.clone(); + } } - } #[cfg(target_os = "linux")] - { - let mut path = Self::get_home(); - path.push(format!(".local/share/logs/{}", APP_NAME)); - std::fs::create_dir_all(&path).ok(); - return path; - } + { + let mut path = Self::get_home(); + path.push(format!(".local/share/logs/{}", APP_NAME)); + std::fs::create_dir_all(&path).ok(); + return path; + } if let Some(path) = Self::path("").parent() { let mut path: PathBuf = path.into(); path.push("log"); @@ -318,21 +332,21 @@ impl Config { pub fn ipc_path(postfix: &str) -> String { #[cfg(windows)] - { - // \\ServerName\pipe\PipeName - // where ServerName is either the name of a remote computer or a period, to specify the local computer. - // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names - format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) - } + { + // \\ServerName\pipe\PipeName + // where ServerName is either the name of a remote computer or a period, to specify the local computer. + // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names + format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) + } #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); - fs::create_dir(&path).ok(); - fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); - path.push(format!("ipc{}", postfix)); - path.to_str().unwrap_or("").to_owned() - } + { + use std::os::unix::fs::PermissionsExt; + let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); + fs::create_dir(&path).ok(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); + path.push(format!("ipc{}", postfix)); + path.to_str().unwrap_or("").to_owned() + } } pub fn icon_path() -> PathBuf { @@ -446,7 +460,7 @@ impl Config { fn get_auto_id() -> Option { #[cfg(any(target_os = "android", target_os = "ios"))] - return None; + return None; let mut id = 0u32; #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Ok(Some(ma)) = mac_address::get_mac_address() { @@ -659,6 +673,45 @@ impl Config { Some(_) => NetworkType::ProxySocks, } } + + pub fn copy_and_reload_config_dir>( + target_username: String, + from: P, + ) -> Result { + let to = Self::path(""); + let to_parent = to.parent().unwrap(); + + let mut options = fs_extra::dir::CopyOptions::new(); + options.overwrite = true; + options.copy_inside = true; + + let mut f = from.as_ref(); + + return match fs_extra::dir::copy(f, to_parent, &options) { + Ok(count) => { + if count > 0 { + log::info!("{}",target_username); + log::info!("{}",f.to_str().unwrap().to_string()); + log::info!("{}",to.to_str().unwrap().to_string()); + + std::process::Command::new("chown") + .arg("-R") + .arg(target_username) + .arg(to.to_str().unwrap().to_string()) + .spawn(); + + CONFIG.write().unwrap().reload(); + CONFIG2.write().unwrap().reload(); + } + + Ok(count > 0) + } + Err(e) => { + log::error!("config copy failed: {}", e); + Err(e) + } + }; + } } const PEERS: &str = "peers"; @@ -757,6 +810,7 @@ impl Fav { #[cfg(test)] mod tests { use super::*; + #[test] fn test_serialize() { let cfg: Config = Default::default(); diff --git a/src/ipc.rs b/src/ipc.rs index e197d804d..bbfc40a31 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,19 +1,10 @@ -use hbb_common::{ - allow_err, bail, bytes, - bytes_codec::BytesCodec, - config::{self, Config}, - futures::StreamExt as _, - futures_util::sink::SinkExt, - log, timeout, tokio, - tokio::io::{AsyncRead, AsyncWrite}, - tokio_util::codec::Framed, - ResultType, -}; +use hbb_common::{allow_err, bail, bytes, bytes_codec::BytesCodec, config::{self, Config}, futures::StreamExt as _, futures_util::sink::SinkExt, log, timeout, tokio, tokio::io::{AsyncRead, AsyncWrite}, tokio_util::codec::Framed, ResultType}; use parity_tokio_ipc::{ Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes, }; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; +use std::path::PathBuf; #[cfg(not(windows))] use std::{fs::File, io::prelude::*}; @@ -92,6 +83,11 @@ pub enum Data { Socks(Option), FS(FS), Test, + ConfigCopyReq { + target_username: String, + dir_path: String, + }, + ConfigCopyResp(Option), } #[tokio::main(flavor = "current_thread")] @@ -129,7 +125,7 @@ pub async fn start(postfix: &str) -> ResultType<()> { pub async fn new_listener(postfix: &str) -> ResultType { let path = Config::ipc_path(postfix); #[cfg(not(windows))] - check_pid(postfix).await; + check_pid(postfix).await; let mut endpoint = Endpoint::new(path.clone()); match SecurityAttributes::allow_everyone_create() { Ok(attr) => endpoint.set_security_attributes(attr), @@ -139,11 +135,11 @@ pub async fn new_listener(postfix: &str) -> ResultType { Ok(incoming) => { log::info!("Started ipc{} server at path: {}", postfix, &path); #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); - write_pid(postfix); - } + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); + write_pid(postfix); + } Ok(incoming) } Err(err) => { @@ -252,6 +248,23 @@ async fn handle(data: Data, stream: &mut Connection) { let t = Config::get_nat_type(); allow_err!(stream.send(&Data::NatType(Some(t))).await); } + Data::ConfigCopyReq { target_username, dir_path } => { + let from = PathBuf::from(dir_path); + if !from.exists() { + allow_err!(stream.send(&Data::ConfigCopyResp(None)).await); + return; + } + + match Config::copy_and_reload_config_dir(target_username, from) { + Ok(result) => { + allow_err!(stream.send(&Data::ConfigCopyResp(Some(result))).await); + } + Err(e) => { + log::error!("copy_and_reload_config_dir failed: {:?}",e); + allow_err!(stream.send(&Data::ConfigCopyResp(Some(false))).await); + } + } + } _ => {} } } @@ -312,8 +325,8 @@ pub struct ConnectionTmpl { pub type Connection = ConnectionTmpl; impl ConnectionTmpl -where - T: AsyncRead + AsyncWrite + std::marker::Unpin, + where + T: AsyncRead + AsyncWrite + std::marker::Unpin, { pub fn new(conn: T) -> Self { Self { diff --git a/src/lib.rs b/src/lib.rs index 2df657ab0..7bac02eeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,4 +27,4 @@ use common::*; pub mod cli; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; -mod lang; +mod lang; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e2d00d0c5..1af4c9f45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ fn main() { common::test_rendezvous_server(); common::test_nat_type(); #[cfg(target_os = "android")] - crate::common::check_software_update(); + crate::common::check_software_update(); mobile::Session::start(""); } @@ -29,53 +29,53 @@ fn main() { return; } #[cfg(not(feature = "inline"))] - { - use hbb_common::env_logger::*; - init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); - } - #[cfg(feature = "inline")] - { - let mut path = hbb_common::config::Config::log_path(); - if args.len() > 0 && args[0].starts_with("--") { - let name = args[0].replace("--", ""); - if !name.is_empty() { - path.push(name); - } + { + use hbb_common::env_logger::*; + init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); + } + #[cfg(feature = "inline")] + { + let mut path = hbb_common::config::Config::log_path(); + if args.len() > 0 && args[0].starts_with("--") { + let name = args[0].replace("--", ""); + if !name.is_empty() { + path.push(name); + } + } + use flexi_logger::*; + Logger::try_with_env_or_str("debug") + .map(|x| { + x.log_to_file(FileSpec::default().directory(path)) + .format(opt_format) + .rotate( + Criterion::Age(Age::Day), + Naming::Timestamps, + Cleanup::KeepLogFiles(6), + ) + .start() + .ok(); + }) + .ok(); } - use flexi_logger::*; - Logger::try_with_env_or_str("debug") - .map(|x| { - x.log_to_file(FileSpec::default().directory(path)) - .format(opt_format) - .rotate( - Criterion::Age(Age::Day), - Naming::Timestamps, - Cleanup::KeepLogFiles(6), - ) - .start() - .ok(); - }) - .ok(); - } if args.is_empty() { std::thread::spawn(move || start_server(false, false)); } else { #[cfg(windows)] - { - if args[0] == "--uninstall" { - if let Err(err) = platform::uninstall_me() { - log::error!("Failed to uninstall: {}", err); + { + if args[0] == "--uninstall" { + if let Err(err) = platform::uninstall_me() { + log::error!("Failed to uninstall: {}", err); + } + return; + } else if args[0] == "--update" { + hbb_common::allow_err!(platform::update_me()); + return; + } else if args[0] == "--reinstall" { + hbb_common::allow_err!(platform::uninstall_me()); + hbb_common::allow_err!(platform::install_me("desktopicon startmenu",)); + return; } - return; - } else if args[0] == "--update" { - hbb_common::allow_err!(platform::update_me()); - return; - } else if args[0] == "--reinstall" { - hbb_common::allow_err!(platform::uninstall_me()); - hbb_common::allow_err!(platform::install_me("desktopicon startmenu",)); - return; } - } if args[0] == "--remove" { if args.len() == 2 { // sleep a while so that process of removed exe exit @@ -101,6 +101,10 @@ fn main() { ipc::set_password(args[1].to_owned()).unwrap(); } return; + } else if cfg!(target_os = "macos") && args[0] == "--daemon" { + log::info!("start --daemon"); + crate::platform::start_daemon(); + return; } } ui::start(&mut args[..]); diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 5834fd024..a79094172 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -333,3 +333,10 @@ pub fn block_input(_v: bool) { pub fn is_installed() -> bool { true } + +pub fn start_daemon(){ + if let Err(err) = crate::ipc::start("_daemon") { + log::error!("Failed to start ipc_daemon: {}", err); + std::process::exit(-1); + } +} diff --git a/src/server.rs b/src/server.rs index 451c18e1b..27cf0061a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use crate::ipc::Data; +use crate::ipc::{ConnectionTmpl, Data}; use connection::{ConnInner, Connection}; use hbb_common::{ allow_err, @@ -9,18 +9,24 @@ use hbb_common::{ message_proto::*, protobuf::{Message as _, ProtobufEnum}, rendezvous_proto::*, - sleep, + sleep, socket_client, sodiumoxide::crypto::{box_, secretbox, sign}, timeout, tokio, ResultType, Stream, - socket_client, }; use service::{GenericService, Service, ServiceTmpl, Subscriber}; +use std::sync::mpsc::RecvError; +use std::time::Duration; use std::{ collections::HashMap, net::SocketAddr, sync::{Arc, Mutex, RwLock, Weak}, }; +use hbb_common::log::info; +#[cfg(target_os = "macos")] +use notify::{watcher, RecursiveMode, Watcher}; +use parity_tokio_ipc::ConnectionClient; + mod audio_service; mod clipboard_service; mod connection; @@ -166,7 +172,7 @@ pub async fn create_relay_connection( secure: bool, ) { if let Err(err) = - create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await + create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await { log::error!( "Failed to create relay connection for {} with uuid {}: {}", @@ -189,7 +195,7 @@ async fn create_relay_connection_( Config::get_any_listen_addr(), CONNECT_TIMEOUT, ) - .await?; + .await?; let mut msg_out = RendezvousMessage::new(); msg_out.set_request_relay(RequestRelay { uuid, @@ -264,10 +270,13 @@ pub fn check_zombie() { #[tokio::main] pub async fn start_server(is_server: bool, _tray: bool) { #[cfg(target_os = "linux")] - { - log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); - log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); - } + { + log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); + log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); + } + + sync_and_watch_config_dir().await; + if is_server { std::thread::spawn(move || { if let Err(err) = crate::ipc::start("") { @@ -298,7 +307,7 @@ pub async fn start_server(is_server: bool, _tray: bool) { } else { allow_err!(conn.send(&Data::ConfirmedKey(None)).await); if let Ok(Some(Data::ConfirmedKey(Some(pair)))) = - conn.next_timeout(1000).await + conn.next_timeout(1000).await { Config::set_key_pair(pair); Config::set_key_confirmed(true); @@ -317,3 +326,72 @@ pub async fn start_server(is_server: bool, _tray: bool) { } } } + +async fn sync_and_watch_config_dir() -> ResultType<()> { + let mut conn = crate::ipc::connect(1000, "_daemon").await?; + + sync_config_dir(&mut conn, "/var/root/Library/Preferences/com.carriez.RustDesk/".to_string()).await?; + + tokio::spawn(async move { + log::info!( + "watching config dir: {}", + Config::path("").to_str().unwrap().to_string() + ); + + let (tx, rx) = std::sync::mpsc::channel(); + let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); + watcher + .watch(Config::path("").as_path(), RecursiveMode::Recursive) + .unwrap(); + + loop { + let ev = rx.recv(); + match ev { + Ok(event) => match event { + notify::DebouncedEvent::Write(path) => { + log::info!( + "config file changed, call ipc_daemon to sync: {}", + path.to_str().unwrap().to_string() + ); + sync_config_dir(&mut conn, Config::path("").to_str().unwrap().to_string()).await; + } + x => { + log::info!("another {:?}", x) + } + }, + Err(e) => println!("watch error: {:?}", e), + } + } + }); + + Ok(()) +} + +async fn sync_config_dir(conn: &mut ConnectionTmpl, path: String) -> ResultType<()> { + allow_err!( + conn.send(&Data::ConfigCopyReq { + target_username: crate::username(), + dir_path: path + }) + .await + ); + if let Ok(Some(data)) = conn.next_timeout(1000).await { + match data { + Data::ConfigCopyResp(result) => match result { + Some(success) => { + if success { + log::info!("copy and reload config dir success"); + } else { + log::info!("copy config dir failed. may be first running"); + } + } + None => {} + }, + x => { + log::info!("receive another {:?}",x) + } + }; + }; + + Ok(()) +} From 88f0f67ee321429c94f3fc2419edd537382917de Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 15:26:57 +0800 Subject: [PATCH 02/13] temp commit --- libs/hbb_common/src/config.rs | 203 +++++++++++++++++++++------------- src/ipc.rs | 83 +++++++++----- src/platform/macos.rs | 1 + src/server.rs | 143 ++++++++++++++---------- 4 files changed, 264 insertions(+), 166 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index e9df2f15c..cb52f8708 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -11,7 +11,6 @@ use std::{ sync::{Arc, Mutex, RwLock}, time::SystemTime, }; -use std::borrow::Borrow; pub const APP_NAME: &str = "RustDesk"; pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; @@ -163,28 +162,28 @@ pub struct PeerInfoSerde { fn patch(path: PathBuf) -> PathBuf { if let Some(_tmp) = path.to_str() { #[cfg(windows)] - return _tmp + return _tmp .replace( "system32\\config\\systemprofile", "ServiceProfiles\\LocalService", ) .into(); #[cfg(target_os = "macos")] - return _tmp.replace("Application Support", "Preferences").into(); + return _tmp.replace("Application Support", "Preferences").into(); #[cfg(target_os = "linux")] - { - if _tmp == "/root" { - if let Ok(output) = std::process::Command::new("whoami").output() { - let user = String::from_utf8_lossy(&output.stdout) - .to_string() - .trim() - .to_owned(); - if user != "root" { - return format!("/home/{}", user).into(); - } + { + if _tmp == "/root" { + if let Ok(output) = std::process::Command::new("whoami").output() { + let user = String::from_utf8_lossy(&output.stdout) + .to_string() + .trim() + .to_owned(); + if user != "root" { + return format!("/home/{}", user).into(); } } } + } } path } @@ -276,7 +275,7 @@ impl Config { pub fn get_home() -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - return Self::path(""); + return Self::path(""); if let Some(path) = dirs_next::home_dir() { patch(path) } else if let Ok(path) = std::env::current_dir() { @@ -288,15 +287,15 @@ impl Config { pub fn path>(p: P) -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - { - let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); - path.push(p); - return path; - } + { + let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); + path.push(p); + return path; + } #[cfg(not(target_os = "macos"))] - let org = ""; + let org = ""; #[cfg(target_os = "macos")] - let org = ORG; + let org = ORG; // /var/root for root if let Some(project) = ProjectDirs::from("", org, APP_NAME) { let mut path = patch(project.config_dir().to_path_buf()); @@ -309,19 +308,19 @@ impl Config { #[allow(unreachable_code)] pub fn log_path() -> PathBuf { #[cfg(target_os = "macos")] - { - if let Some(path) = dirs_next::home_dir().as_mut() { - path.push(format!("Library/Logs/{}", APP_NAME)); - return path.clone(); - } + { + if let Some(path) = dirs_next::home_dir().as_mut() { + path.push(format!("Library/Logs/{}", APP_NAME)); + return path.clone(); } + } #[cfg(target_os = "linux")] - { - let mut path = Self::get_home(); - path.push(format!(".local/share/logs/{}", APP_NAME)); - std::fs::create_dir_all(&path).ok(); - return path; - } + { + let mut path = Self::get_home(); + path.push(format!(".local/share/logs/{}", APP_NAME)); + std::fs::create_dir_all(&path).ok(); + return path; + } if let Some(path) = Self::path("").parent() { let mut path: PathBuf = path.into(); path.push("log"); @@ -332,21 +331,21 @@ impl Config { pub fn ipc_path(postfix: &str) -> String { #[cfg(windows)] - { - // \\ServerName\pipe\PipeName - // where ServerName is either the name of a remote computer or a period, to specify the local computer. - // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names - format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) - } + { + // \\ServerName\pipe\PipeName + // where ServerName is either the name of a remote computer or a period, to specify the local computer. + // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names + format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) + } #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); - fs::create_dir(&path).ok(); - fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); - path.push(format!("ipc{}", postfix)); - path.to_str().unwrap_or("").to_owned() - } + { + use std::os::unix::fs::PermissionsExt; + let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); + fs::create_dir(&path).ok(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); + path.push(format!("ipc{}", postfix)); + path.to_str().unwrap_or("").to_owned() + } } pub fn icon_path() -> PathBuf { @@ -460,7 +459,7 @@ impl Config { fn get_auto_id() -> Option { #[cfg(any(target_os = "android", target_os = "ios"))] - return None; + return None; let mut id = 0u32; #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Ok(Some(ma)) = mac_address::get_mac_address() { @@ -674,43 +673,91 @@ impl Config { } } - pub fn copy_and_reload_config_dir>( - target_username: String, - from: P, - ) -> Result { - let to = Self::path(""); - let to_parent = to.parent().unwrap(); + pub fn sync_config_to_user>(target_username: String, to_dir: P) -> bool { + let config1_root_file_path = Config::file_(""); + let config1_filename = config1_root_file_path.file_name(); - let mut options = fs_extra::dir::CopyOptions::new(); - options.overwrite = true; - options.copy_inside = true; + let config2_root_file_path = Config::file_("2"); + let config2_filename = config2_root_file_path.file_name(); - let mut f = from.as_ref(); + let config1_to_file_path = to_dir + .as_ref() + .join(PathBuf::from(&config1_filename.unwrap())); + let config2_to_file_path = to_dir + .as_ref() + .join(PathBuf::from(&config2_filename.unwrap())); - return match fs_extra::dir::copy(f, to_parent, &options) { - Ok(count) => { - if count > 0 { - log::info!("{}",target_username); - log::info!("{}",f.to_str().unwrap().to_string()); - log::info!("{}",to.to_str().unwrap().to_string()); + log::info!( + "config1_root_path:{}", + &config1_root_file_path.as_path().to_str().unwrap() + ); + log::info!( + "config2_root_path:{}", + &config2_root_file_path.as_path().to_str().unwrap() + ); + log::info!( + "config1_to_path:{}", + &config1_to_file_path.as_path().to_str().unwrap() + ); + log::info!( + "config2_to_path:{}", + &config2_to_file_path.as_path().to_str().unwrap() + ); - std::process::Command::new("chown") - .arg("-R") - .arg(target_username) - .arg(to.to_str().unwrap().to_string()) - .spawn(); + match std::fs::copy(&config1_root_file_path, &config1_to_file_path) { + Err(e) => log::error!( + "copy config {} to user failed: {}", + config1_filename.unwrap().to_str().unwrap(), + e + ), + _ => {} + } - CONFIG.write().unwrap().reload(); - CONFIG2.write().unwrap().reload(); + match std::fs::copy(&config2_root_file_path, &config2_to_file_path) { + Err(e) => log::error!( + "copy config {} to user failed: {}", + config2_filename.unwrap().to_str().unwrap(), + e + ), + _ => {} + } + + let success = std::process::Command::new("chown") + .arg(&target_username.to_string()) + .arg(&config1_to_file_path.to_str().unwrap().to_string()) + .arg(&config2_to_file_path.to_str().unwrap().to_string()) + .spawn() + .is_ok(); + + if success { + CONFIG.write().unwrap().reload(); + CONFIG2.write().unwrap().reload(); + } + + return success; + } + + pub fn sync_config_to_root>(from_file_path: P) -> bool { + if let Some(filename) = from_file_path.as_ref().file_name() { + let to = Config::path(filename); + return match std::fs::copy(from_file_path, &to) { + Ok(count) => { + if count > 0 { + return std::process::Command::new("chown") + .arg("root") + .arg(&to.to_str().unwrap().to_string()) + .spawn() + .is_ok(); + } + false } - - Ok(count > 0) - } - Err(e) => { - log::error!("config copy failed: {}", e); - Err(e) - } - }; + Err(e) => { + log::error!("sync_config_to_root failed: {}", e); + false + } + }; + } + false } } diff --git a/src/ipc.rs b/src/ipc.rs index bbfc40a31..59e406430 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,10 +1,20 @@ -use hbb_common::{allow_err, bail, bytes, bytes_codec::BytesCodec, config::{self, Config}, futures::StreamExt as _, futures_util::sink::SinkExt, log, timeout, tokio, tokio::io::{AsyncRead, AsyncWrite}, tokio_util::codec::Framed, ResultType}; +use hbb_common::log::info; +use hbb_common::{ + allow_err, bail, bytes, + bytes_codec::BytesCodec, + config::{self, Config}, + futures::StreamExt as _, + futures_util::sink::SinkExt, + log, timeout, tokio, + tokio::io::{AsyncRead, AsyncWrite}, + tokio_util::codec::Framed, + ResultType, +}; use parity_tokio_ipc::{ Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes, }; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; -use std::path::PathBuf; #[cfg(not(windows))] use std::{fs::File, io::prelude::*}; @@ -83,17 +93,22 @@ pub enum Data { Socks(Option), FS(FS), Test, - ConfigCopyReq { - target_username: String, - dir_path: String, + SyncConfigToRootReq { + from: String, }, - ConfigCopyResp(Option), + SyncConfigToRootResp(bool), + SyncConfigToUserReq { + username: String, + to: String, + }, + SyncConfigToUserResp(bool), } #[tokio::main(flavor = "current_thread")] pub async fn start(postfix: &str) -> ResultType<()> { let mut incoming = new_listener(postfix).await?; loop { + log::info!("begin loop"); if let Some(result) = incoming.next().await { match result { Ok(stream) => { @@ -101,13 +116,16 @@ pub async fn start(postfix: &str) -> ResultType<()> { let postfix = postfix.to_owned(); tokio::spawn(async move { loop { + log::info!("begin loop"); match stream.next().await { Err(err) => { log::trace!("ipc{} connection closed: {}", postfix, err); break; } Ok(Some(data)) => { + log::info!("begin handle"); handle(data, &mut stream).await; + log::info!("end handle"); } _ => {} } @@ -125,7 +143,7 @@ pub async fn start(postfix: &str) -> ResultType<()> { pub async fn new_listener(postfix: &str) -> ResultType { let path = Config::ipc_path(postfix); #[cfg(not(windows))] - check_pid(postfix).await; + check_pid(postfix).await; let mut endpoint = Endpoint::new(path.clone()); match SecurityAttributes::allow_everyone_create() { Ok(attr) => endpoint.set_security_attributes(attr), @@ -135,11 +153,11 @@ pub async fn new_listener(postfix: &str) -> ResultType { Ok(incoming) => { log::info!("Started ipc{} server at path: {}", postfix, &path); #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); - write_pid(postfix); - } + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); + write_pid(postfix); + } Ok(incoming) } Err(err) => { @@ -248,22 +266,27 @@ async fn handle(data: Data, stream: &mut Connection) { let t = Config::get_nat_type(); allow_err!(stream.send(&Data::NatType(Some(t))).await); } - Data::ConfigCopyReq { target_username, dir_path } => { - let from = PathBuf::from(dir_path); - if !from.exists() { - allow_err!(stream.send(&Data::ConfigCopyResp(None)).await); - return; - } - - match Config::copy_and_reload_config_dir(target_username, from) { - Ok(result) => { - allow_err!(stream.send(&Data::ConfigCopyResp(Some(result))).await); - } - Err(e) => { - log::error!("copy_and_reload_config_dir failed: {:?}",e); - allow_err!(stream.send(&Data::ConfigCopyResp(Some(false))).await); - } - } + Data::SyncConfigToRootReq { from } => { + info!("begin SyncConfigToRootReq, {}", from); + allow_err!( + stream + .send(&Data::SyncConfigToRootResp(Config::sync_config_to_root( + from + ))) + .await + ); + info!("begin SyncConfigToRootReq end"); + } + Data::SyncConfigToUserReq { username, to } => { + info!("begin SyncConfigToUserReq,{},{}", username, to); + allow_err!( + stream + .send(&Data::SyncConfigToUserResp(Config::sync_config_to_user( + username, to + ))) + .await + ); + info!("begin SyncConfigToUserReq end"); } _ => {} } @@ -325,8 +348,8 @@ pub struct ConnectionTmpl { pub type Connection = ConnectionTmpl; impl ConnectionTmpl - where - T: AsyncRead + AsyncWrite + std::marker::Unpin, +where + T: AsyncRead + AsyncWrite + std::marker::Unpin, { pub fn new(conn: T) -> Self { Self { diff --git a/src/platform/macos.rs b/src/platform/macos.rs index a79094172..f278fdf9c 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -335,6 +335,7 @@ pub fn is_installed() -> bool { } pub fn start_daemon(){ + log::info!("{}",crate::username()); if let Err(err) = crate::ipc::start("_daemon") { log::error!("Failed to start ipc_daemon: {}", err); std::process::exit(-1); diff --git a/src/server.rs b/src/server.rs index 27cf0061a..38da11b5c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -14,7 +14,7 @@ use hbb_common::{ timeout, tokio, ResultType, Stream, }; use service::{GenericService, Service, ServiceTmpl, Subscriber}; -use std::sync::mpsc::RecvError; +use std::path::PathBuf; use std::time::Duration; use std::{ collections::HashMap, @@ -22,7 +22,6 @@ use std::{ sync::{Arc, Mutex, RwLock, Weak}, }; -use hbb_common::log::info; #[cfg(target_os = "macos")] use notify::{watcher, RecursiveMode, Watcher}; use parity_tokio_ipc::ConnectionClient; @@ -172,7 +171,7 @@ pub async fn create_relay_connection( secure: bool, ) { if let Err(err) = - create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await + create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await { log::error!( "Failed to create relay connection for {} with uuid {}: {}", @@ -195,7 +194,7 @@ async fn create_relay_connection_( Config::get_any_listen_addr(), CONNECT_TIMEOUT, ) - .await?; + .await?; let mut msg_out = RendezvousMessage::new(); msg_out.set_request_relay(RequestRelay { uuid, @@ -270,12 +269,14 @@ pub fn check_zombie() { #[tokio::main] pub async fn start_server(is_server: bool, _tray: bool) { #[cfg(target_os = "linux")] - { - log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); - log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); - } + { + log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); + log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); + } - sync_and_watch_config_dir().await; + tokio::spawn(async { sync_and_watch_config_dir().await }); + + log::info!("enter server"); if is_server { std::thread::spawn(move || { @@ -307,7 +308,7 @@ pub async fn start_server(is_server: bool, _tray: bool) { } else { allow_err!(conn.send(&Data::ConfirmedKey(None)).await); if let Ok(Some(Data::ConfirmedKey(Some(pair)))) = - conn.next_timeout(1000).await + conn.next_timeout(1000).await { Config::set_key_pair(pair); Config::set_key_confirmed(true); @@ -327,68 +328,94 @@ pub async fn start_server(is_server: bool, _tray: bool) { } } -async fn sync_and_watch_config_dir() -> ResultType<()> { - let mut conn = crate::ipc::connect(1000, "_daemon").await?; +async fn sync_and_watch_config_dir() { + if crate::username() == "root"{ + return; + } - sync_config_dir(&mut conn, "/var/root/Library/Preferences/com.carriez.RustDesk/".to_string()).await?; + match crate::ipc::connect(1000, "_daemon").await { + Ok(mut conn) => { + sync_config_to_user(&mut conn).await; - tokio::spawn(async move { - log::info!( - "watching config dir: {}", - Config::path("").to_str().unwrap().to_string() - ); + log::info!( + "watching config dir: {}", + Config::path("").to_str().unwrap().to_string() + ); - let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); - watcher - .watch(Config::path("").as_path(), RecursiveMode::Recursive) - .unwrap(); + let (tx, rx) = std::sync::mpsc::channel(); + let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); + watcher + .watch(Config::path("").as_path(), RecursiveMode::Recursive) + .unwrap(); - loop { - let ev = rx.recv(); - match ev { - Ok(event) => match event { - notify::DebouncedEvent::Write(path) => { - log::info!( - "config file changed, call ipc_daemon to sync: {}", - path.to_str().unwrap().to_string() - ); - sync_config_dir(&mut conn, Config::path("").to_str().unwrap().to_string()).await; - } - x => { - log::info!("another {:?}", x) - } - }, - Err(e) => println!("watch error: {:?}", e), + loop { + let ev = rx.recv(); + match ev { + Ok(event) => match event { + notify::DebouncedEvent::Write(path) => { + log::info!( + "config file changed, call ipc_daemon to sync: {}", + path.to_str().unwrap().to_string() + ); + sync_config_to_root(&mut conn, path).await; + log::info!("sync end"); + } + x => { + log::info!("another {:?}", x) + } + }, + Err(e) => println!("watch error: {:?}", e), + } } } - }); - - Ok(()) + Err(e) => { + log::info!("connect ipc_daemon failed, skip config sync"); + return; + } + } } -async fn sync_config_dir(conn: &mut ConnectionTmpl, path: String) -> ResultType<()> { +async fn sync_config_to_user(conn: &mut ConnectionTmpl) -> ResultType<()> { allow_err!( - conn.send(&Data::ConfigCopyReq { - target_username: crate::username(), - dir_path: path + conn.send(&Data::SyncConfigToUserReq { + username: crate::username(), + to: Config::path("").to_str().unwrap().to_string(), }) .await ); - if let Ok(Some(data)) = conn.next_timeout(1000).await { + + if let Some(data) = conn.next_timeout(2000).await? { match data { - Data::ConfigCopyResp(result) => match result { - Some(success) => { - if success { - log::info!("copy and reload config dir success"); - } else { - log::info!("copy config dir failed. may be first running"); - } - } - None => {} - }, + Data::SyncConfigToUserResp(success) => { + log::info!("copy and reload config dir success: {:?}", success); + } x => { - log::info!("receive another {:?}",x) + log::info!("receive another {:?}", x) + } + }; + }; + + Ok(()) +} + +async fn sync_config_to_root( + conn: &mut ConnectionTmpl, + from: PathBuf, +) -> ResultType<()> { + allow_err!( + conn.send(&Data::SyncConfigToRootReq { + from: from.to_str().unwrap().to_string() + }) + .await + ); + + if let Some(data) = conn.next_timeout(2000).await? { + match data { + Data::SyncConfigToRootResp(success) => { + log::info!("copy config to root dir success: {:?}", success); + } + x => { + log::info!("receive another {:?}", x) } }; }; From 1995f9fa4ee88a30ab78cfb1d3da55b55259f360 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 16:06:51 +0800 Subject: [PATCH 03/13] Revert "temp commit" This reverts commit 88f0f67ee321429c94f3fc2419edd537382917de. --- libs/hbb_common/src/config.rs | 203 +++++++++++++--------------------- src/ipc.rs | 83 +++++--------- src/platform/macos.rs | 1 - src/server.rs | 159 +++++++++++--------------- 4 files changed, 174 insertions(+), 272 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index cb52f8708..e9df2f15c 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -11,6 +11,7 @@ use std::{ sync::{Arc, Mutex, RwLock}, time::SystemTime, }; +use std::borrow::Borrow; pub const APP_NAME: &str = "RustDesk"; pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; @@ -162,28 +163,28 @@ pub struct PeerInfoSerde { fn patch(path: PathBuf) -> PathBuf { if let Some(_tmp) = path.to_str() { #[cfg(windows)] - return _tmp + return _tmp .replace( "system32\\config\\systemprofile", "ServiceProfiles\\LocalService", ) .into(); #[cfg(target_os = "macos")] - return _tmp.replace("Application Support", "Preferences").into(); + return _tmp.replace("Application Support", "Preferences").into(); #[cfg(target_os = "linux")] - { - if _tmp == "/root" { - if let Ok(output) = std::process::Command::new("whoami").output() { - let user = String::from_utf8_lossy(&output.stdout) - .to_string() - .trim() - .to_owned(); - if user != "root" { - return format!("/home/{}", user).into(); + { + if _tmp == "/root" { + if let Ok(output) = std::process::Command::new("whoami").output() { + let user = String::from_utf8_lossy(&output.stdout) + .to_string() + .trim() + .to_owned(); + if user != "root" { + return format!("/home/{}", user).into(); + } } } } - } } path } @@ -275,7 +276,7 @@ impl Config { pub fn get_home() -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - return Self::path(""); + return Self::path(""); if let Some(path) = dirs_next::home_dir() { patch(path) } else if let Ok(path) = std::env::current_dir() { @@ -287,15 +288,15 @@ impl Config { pub fn path>(p: P) -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - { - let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); - path.push(p); - return path; - } + { + let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); + path.push(p); + return path; + } #[cfg(not(target_os = "macos"))] - let org = ""; + let org = ""; #[cfg(target_os = "macos")] - let org = ORG; + let org = ORG; // /var/root for root if let Some(project) = ProjectDirs::from("", org, APP_NAME) { let mut path = patch(project.config_dir().to_path_buf()); @@ -308,19 +309,19 @@ impl Config { #[allow(unreachable_code)] pub fn log_path() -> PathBuf { #[cfg(target_os = "macos")] - { - if let Some(path) = dirs_next::home_dir().as_mut() { - path.push(format!("Library/Logs/{}", APP_NAME)); - return path.clone(); + { + if let Some(path) = dirs_next::home_dir().as_mut() { + path.push(format!("Library/Logs/{}", APP_NAME)); + return path.clone(); + } } - } #[cfg(target_os = "linux")] - { - let mut path = Self::get_home(); - path.push(format!(".local/share/logs/{}", APP_NAME)); - std::fs::create_dir_all(&path).ok(); - return path; - } + { + let mut path = Self::get_home(); + path.push(format!(".local/share/logs/{}", APP_NAME)); + std::fs::create_dir_all(&path).ok(); + return path; + } if let Some(path) = Self::path("").parent() { let mut path: PathBuf = path.into(); path.push("log"); @@ -331,21 +332,21 @@ impl Config { pub fn ipc_path(postfix: &str) -> String { #[cfg(windows)] - { - // \\ServerName\pipe\PipeName - // where ServerName is either the name of a remote computer or a period, to specify the local computer. - // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names - format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) - } + { + // \\ServerName\pipe\PipeName + // where ServerName is either the name of a remote computer or a period, to specify the local computer. + // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names + format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) + } #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); - fs::create_dir(&path).ok(); - fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); - path.push(format!("ipc{}", postfix)); - path.to_str().unwrap_or("").to_owned() - } + { + use std::os::unix::fs::PermissionsExt; + let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); + fs::create_dir(&path).ok(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); + path.push(format!("ipc{}", postfix)); + path.to_str().unwrap_or("").to_owned() + } } pub fn icon_path() -> PathBuf { @@ -459,7 +460,7 @@ impl Config { fn get_auto_id() -> Option { #[cfg(any(target_os = "android", target_os = "ios"))] - return None; + return None; let mut id = 0u32; #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Ok(Some(ma)) = mac_address::get_mac_address() { @@ -673,91 +674,43 @@ impl Config { } } - pub fn sync_config_to_user>(target_username: String, to_dir: P) -> bool { - let config1_root_file_path = Config::file_(""); - let config1_filename = config1_root_file_path.file_name(); + pub fn copy_and_reload_config_dir>( + target_username: String, + from: P, + ) -> Result { + let to = Self::path(""); + let to_parent = to.parent().unwrap(); - let config2_root_file_path = Config::file_("2"); - let config2_filename = config2_root_file_path.file_name(); + let mut options = fs_extra::dir::CopyOptions::new(); + options.overwrite = true; + options.copy_inside = true; - let config1_to_file_path = to_dir - .as_ref() - .join(PathBuf::from(&config1_filename.unwrap())); - let config2_to_file_path = to_dir - .as_ref() - .join(PathBuf::from(&config2_filename.unwrap())); + let mut f = from.as_ref(); - log::info!( - "config1_root_path:{}", - &config1_root_file_path.as_path().to_str().unwrap() - ); - log::info!( - "config2_root_path:{}", - &config2_root_file_path.as_path().to_str().unwrap() - ); - log::info!( - "config1_to_path:{}", - &config1_to_file_path.as_path().to_str().unwrap() - ); - log::info!( - "config2_to_path:{}", - &config2_to_file_path.as_path().to_str().unwrap() - ); + return match fs_extra::dir::copy(f, to_parent, &options) { + Ok(count) => { + if count > 0 { + log::info!("{}",target_username); + log::info!("{}",f.to_str().unwrap().to_string()); + log::info!("{}",to.to_str().unwrap().to_string()); - match std::fs::copy(&config1_root_file_path, &config1_to_file_path) { - Err(e) => log::error!( - "copy config {} to user failed: {}", - config1_filename.unwrap().to_str().unwrap(), - e - ), - _ => {} - } + std::process::Command::new("chown") + .arg("-R") + .arg(target_username) + .arg(to.to_str().unwrap().to_string()) + .spawn(); - match std::fs::copy(&config2_root_file_path, &config2_to_file_path) { - Err(e) => log::error!( - "copy config {} to user failed: {}", - config2_filename.unwrap().to_str().unwrap(), - e - ), - _ => {} - } - - let success = std::process::Command::new("chown") - .arg(&target_username.to_string()) - .arg(&config1_to_file_path.to_str().unwrap().to_string()) - .arg(&config2_to_file_path.to_str().unwrap().to_string()) - .spawn() - .is_ok(); - - if success { - CONFIG.write().unwrap().reload(); - CONFIG2.write().unwrap().reload(); - } - - return success; - } - - pub fn sync_config_to_root>(from_file_path: P) -> bool { - if let Some(filename) = from_file_path.as_ref().file_name() { - let to = Config::path(filename); - return match std::fs::copy(from_file_path, &to) { - Ok(count) => { - if count > 0 { - return std::process::Command::new("chown") - .arg("root") - .arg(&to.to_str().unwrap().to_string()) - .spawn() - .is_ok(); - } - false + CONFIG.write().unwrap().reload(); + CONFIG2.write().unwrap().reload(); } - Err(e) => { - log::error!("sync_config_to_root failed: {}", e); - false - } - }; - } - false + + Ok(count > 0) + } + Err(e) => { + log::error!("config copy failed: {}", e); + Err(e) + } + }; } } diff --git a/src/ipc.rs b/src/ipc.rs index 59e406430..bbfc40a31 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,20 +1,10 @@ -use hbb_common::log::info; -use hbb_common::{ - allow_err, bail, bytes, - bytes_codec::BytesCodec, - config::{self, Config}, - futures::StreamExt as _, - futures_util::sink::SinkExt, - log, timeout, tokio, - tokio::io::{AsyncRead, AsyncWrite}, - tokio_util::codec::Framed, - ResultType, -}; +use hbb_common::{allow_err, bail, bytes, bytes_codec::BytesCodec, config::{self, Config}, futures::StreamExt as _, futures_util::sink::SinkExt, log, timeout, tokio, tokio::io::{AsyncRead, AsyncWrite}, tokio_util::codec::Framed, ResultType}; use parity_tokio_ipc::{ Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes, }; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; +use std::path::PathBuf; #[cfg(not(windows))] use std::{fs::File, io::prelude::*}; @@ -93,22 +83,17 @@ pub enum Data { Socks(Option), FS(FS), Test, - SyncConfigToRootReq { - from: String, + ConfigCopyReq { + target_username: String, + dir_path: String, }, - SyncConfigToRootResp(bool), - SyncConfigToUserReq { - username: String, - to: String, - }, - SyncConfigToUserResp(bool), + ConfigCopyResp(Option), } #[tokio::main(flavor = "current_thread")] pub async fn start(postfix: &str) -> ResultType<()> { let mut incoming = new_listener(postfix).await?; loop { - log::info!("begin loop"); if let Some(result) = incoming.next().await { match result { Ok(stream) => { @@ -116,16 +101,13 @@ pub async fn start(postfix: &str) -> ResultType<()> { let postfix = postfix.to_owned(); tokio::spawn(async move { loop { - log::info!("begin loop"); match stream.next().await { Err(err) => { log::trace!("ipc{} connection closed: {}", postfix, err); break; } Ok(Some(data)) => { - log::info!("begin handle"); handle(data, &mut stream).await; - log::info!("end handle"); } _ => {} } @@ -143,7 +125,7 @@ pub async fn start(postfix: &str) -> ResultType<()> { pub async fn new_listener(postfix: &str) -> ResultType { let path = Config::ipc_path(postfix); #[cfg(not(windows))] - check_pid(postfix).await; + check_pid(postfix).await; let mut endpoint = Endpoint::new(path.clone()); match SecurityAttributes::allow_everyone_create() { Ok(attr) => endpoint.set_security_attributes(attr), @@ -153,11 +135,11 @@ pub async fn new_listener(postfix: &str) -> ResultType { Ok(incoming) => { log::info!("Started ipc{} server at path: {}", postfix, &path); #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); - write_pid(postfix); - } + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); + write_pid(postfix); + } Ok(incoming) } Err(err) => { @@ -266,27 +248,22 @@ async fn handle(data: Data, stream: &mut Connection) { let t = Config::get_nat_type(); allow_err!(stream.send(&Data::NatType(Some(t))).await); } - Data::SyncConfigToRootReq { from } => { - info!("begin SyncConfigToRootReq, {}", from); - allow_err!( - stream - .send(&Data::SyncConfigToRootResp(Config::sync_config_to_root( - from - ))) - .await - ); - info!("begin SyncConfigToRootReq end"); - } - Data::SyncConfigToUserReq { username, to } => { - info!("begin SyncConfigToUserReq,{},{}", username, to); - allow_err!( - stream - .send(&Data::SyncConfigToUserResp(Config::sync_config_to_user( - username, to - ))) - .await - ); - info!("begin SyncConfigToUserReq end"); + Data::ConfigCopyReq { target_username, dir_path } => { + let from = PathBuf::from(dir_path); + if !from.exists() { + allow_err!(stream.send(&Data::ConfigCopyResp(None)).await); + return; + } + + match Config::copy_and_reload_config_dir(target_username, from) { + Ok(result) => { + allow_err!(stream.send(&Data::ConfigCopyResp(Some(result))).await); + } + Err(e) => { + log::error!("copy_and_reload_config_dir failed: {:?}",e); + allow_err!(stream.send(&Data::ConfigCopyResp(Some(false))).await); + } + } } _ => {} } @@ -348,8 +325,8 @@ pub struct ConnectionTmpl { pub type Connection = ConnectionTmpl; impl ConnectionTmpl -where - T: AsyncRead + AsyncWrite + std::marker::Unpin, + where + T: AsyncRead + AsyncWrite + std::marker::Unpin, { pub fn new(conn: T) -> Self { Self { diff --git a/src/platform/macos.rs b/src/platform/macos.rs index f278fdf9c..a79094172 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -335,7 +335,6 @@ pub fn is_installed() -> bool { } pub fn start_daemon(){ - log::info!("{}",crate::username()); if let Err(err) = crate::ipc::start("_daemon") { log::error!("Failed to start ipc_daemon: {}", err); std::process::exit(-1); diff --git a/src/server.rs b/src/server.rs index 38da11b5c..27cf0061a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -14,7 +14,7 @@ use hbb_common::{ timeout, tokio, ResultType, Stream, }; use service::{GenericService, Service, ServiceTmpl, Subscriber}; -use std::path::PathBuf; +use std::sync::mpsc::RecvError; use std::time::Duration; use std::{ collections::HashMap, @@ -22,6 +22,7 @@ use std::{ sync::{Arc, Mutex, RwLock, Weak}, }; +use hbb_common::log::info; #[cfg(target_os = "macos")] use notify::{watcher, RecursiveMode, Watcher}; use parity_tokio_ipc::ConnectionClient; @@ -171,7 +172,7 @@ pub async fn create_relay_connection( secure: bool, ) { if let Err(err) = - create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await + create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await { log::error!( "Failed to create relay connection for {} with uuid {}: {}", @@ -194,7 +195,7 @@ async fn create_relay_connection_( Config::get_any_listen_addr(), CONNECT_TIMEOUT, ) - .await?; + .await?; let mut msg_out = RendezvousMessage::new(); msg_out.set_request_relay(RequestRelay { uuid, @@ -269,14 +270,12 @@ pub fn check_zombie() { #[tokio::main] pub async fn start_server(is_server: bool, _tray: bool) { #[cfg(target_os = "linux")] - { - log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); - log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); - } + { + log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); + log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); + } - tokio::spawn(async { sync_and_watch_config_dir().await }); - - log::info!("enter server"); + sync_and_watch_config_dir().await; if is_server { std::thread::spawn(move || { @@ -308,7 +307,7 @@ pub async fn start_server(is_server: bool, _tray: bool) { } else { allow_err!(conn.send(&Data::ConfirmedKey(None)).await); if let Ok(Some(Data::ConfirmedKey(Some(pair)))) = - conn.next_timeout(1000).await + conn.next_timeout(1000).await { Config::set_key_pair(pair); Config::set_key_confirmed(true); @@ -328,94 +327,68 @@ pub async fn start_server(is_server: bool, _tray: bool) { } } -async fn sync_and_watch_config_dir() { - if crate::username() == "root"{ - return; - } +async fn sync_and_watch_config_dir() -> ResultType<()> { + let mut conn = crate::ipc::connect(1000, "_daemon").await?; - match crate::ipc::connect(1000, "_daemon").await { - Ok(mut conn) => { - sync_config_to_user(&mut conn).await; + sync_config_dir(&mut conn, "/var/root/Library/Preferences/com.carriez.RustDesk/".to_string()).await?; - log::info!( - "watching config dir: {}", - Config::path("").to_str().unwrap().to_string() - ); + tokio::spawn(async move { + log::info!( + "watching config dir: {}", + Config::path("").to_str().unwrap().to_string() + ); - let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); - watcher - .watch(Config::path("").as_path(), RecursiveMode::Recursive) - .unwrap(); + let (tx, rx) = std::sync::mpsc::channel(); + let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); + watcher + .watch(Config::path("").as_path(), RecursiveMode::Recursive) + .unwrap(); - loop { - let ev = rx.recv(); - match ev { - Ok(event) => match event { - notify::DebouncedEvent::Write(path) => { - log::info!( - "config file changed, call ipc_daemon to sync: {}", - path.to_str().unwrap().to_string() - ); - sync_config_to_root(&mut conn, path).await; - log::info!("sync end"); - } - x => { - log::info!("another {:?}", x) - } - }, - Err(e) => println!("watch error: {:?}", e), + loop { + let ev = rx.recv(); + match ev { + Ok(event) => match event { + notify::DebouncedEvent::Write(path) => { + log::info!( + "config file changed, call ipc_daemon to sync: {}", + path.to_str().unwrap().to_string() + ); + sync_config_dir(&mut conn, Config::path("").to_str().unwrap().to_string()).await; + } + x => { + log::info!("another {:?}", x) + } + }, + Err(e) => println!("watch error: {:?}", e), + } + } + }); + + Ok(()) +} + +async fn sync_config_dir(conn: &mut ConnectionTmpl, path: String) -> ResultType<()> { + allow_err!( + conn.send(&Data::ConfigCopyReq { + target_username: crate::username(), + dir_path: path + }) + .await + ); + if let Ok(Some(data)) = conn.next_timeout(1000).await { + match data { + Data::ConfigCopyResp(result) => match result { + Some(success) => { + if success { + log::info!("copy and reload config dir success"); + } else { + log::info!("copy config dir failed. may be first running"); + } } - } - } - Err(e) => { - log::info!("connect ipc_daemon failed, skip config sync"); - return; - } - } -} - -async fn sync_config_to_user(conn: &mut ConnectionTmpl) -> ResultType<()> { - allow_err!( - conn.send(&Data::SyncConfigToUserReq { - username: crate::username(), - to: Config::path("").to_str().unwrap().to_string(), - }) - .await - ); - - if let Some(data) = conn.next_timeout(2000).await? { - match data { - Data::SyncConfigToUserResp(success) => { - log::info!("copy and reload config dir success: {:?}", success); - } + None => {} + }, x => { - log::info!("receive another {:?}", x) - } - }; - }; - - Ok(()) -} - -async fn sync_config_to_root( - conn: &mut ConnectionTmpl, - from: PathBuf, -) -> ResultType<()> { - allow_err!( - conn.send(&Data::SyncConfigToRootReq { - from: from.to_str().unwrap().to_string() - }) - .await - ); - - if let Some(data) = conn.next_timeout(2000).await? { - match data { - Data::SyncConfigToRootResp(success) => { - log::info!("copy config to root dir success: {:?}", success); - } - x => { - log::info!("receive another {:?}", x) + log::info!("receive another {:?}",x) } }; }; From e51e5ac4b12fd4eb7526c3abdd26b816e76a2dfd Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 16:07:18 +0800 Subject: [PATCH 04/13] Revert "temp commit" This reverts commit 2e03ca19f6afe9bb705e041af3b97e2ddb398ba7. --- Cargo.lock | 77 ----------------- Cargo.toml | 1 - libs/hbb_common/Cargo.toml | 3 - libs/hbb_common/src/config.rs | 154 +++++++++++----------------------- src/ipc.rs | 51 +++++------ src/lib.rs | 2 +- src/main.rs | 82 +++++++++--------- src/platform/macos.rs | 7 -- src/server.rs | 98 +++------------------- 9 files changed, 119 insertions(+), 356 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c3f27000..1ea2e7c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,31 +1115,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -name = "fsevent" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -dependencies = [ - "bitflags", - "fsevent-sys", -] - -[[package]] -name = "fsevent-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" -dependencies = [ - "libc", -] - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1648,7 +1623,6 @@ dependencies = [ "dirs-next", "env_logger 0.9.0", "filetime", - "fs_extra", "futures", "futures-util", "lazy_static", @@ -1724,26 +1698,6 @@ dependencies = [ "tiff", ] -[[package]] -name = "inotify" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" -dependencies = [ - "bitflags", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - [[package]] name = "instant" version = "0.1.12" @@ -2106,18 +2060,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio 0.6.23", - "slab", -] - [[package]] name = "mio-named-pipes" version = "0.1.7" @@ -2282,24 +2224,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "notify" -version = "4.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" -dependencies = [ - "bitflags", - "filetime", - "fsevent", - "fsevent-sys", - "inotify", - "libc", - "mio 0.6.23", - "mio-extras", - "walkdir", - "winapi 0.3.9", -] - [[package]] name = "ntapi" version = "0.3.6" @@ -3229,7 +3153,6 @@ dependencies = [ "mac_address", "machine-uid", "magnum-opus", - "notify", "objc", "parity-tokio-ipc", "psutil", diff --git a/Cargo.toml b/Cargo.toml index 9a13bedaf..6a9325e25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,6 @@ cocoa = "0.24" dispatch = "0.2" core-foundation = "0.9" core-graphics = "0.22" -notify = "4.0.17" [target.'cfg(target_os = "linux")'.dependencies] libpulse-simple-binding = "2.24" diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index 485e91ba0..d1868f5b5 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -43,9 +43,6 @@ protobuf-codegen-pure = "3.0.0-alpha.2" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winuser"] } -[target.'cfg(target_os = "macos")'.dependencies] -fs_extra = "1.2.0" - [dev-dependencies] toml = "0.5" serde_json = "1.0" diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index e9df2f15c..d248f0c28 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -11,7 +11,6 @@ use std::{ sync::{Arc, Mutex, RwLock}, time::SystemTime, }; -use std::borrow::Borrow; pub const APP_NAME: &str = "RustDesk"; pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; @@ -70,8 +69,7 @@ pub struct Config { #[serde(default)] salt: String, #[serde(default)] - key_pair: (Vec, Vec), - // sk, pk + key_pair: (Vec, Vec), // sk, pk #[serde(default)] key_confirmed: bool, #[serde(default)] @@ -92,8 +90,7 @@ pub struct Socks5Server { #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct Config2 { #[serde(default)] - remote_id: String, - // latest used one + remote_id: String, // latest used one #[serde(default)] size: Size, #[serde(default)] @@ -122,8 +119,7 @@ pub struct PeerConfig { #[serde(default)] pub size_pf: Size, #[serde(default)] - pub view_style: String, - // original (default), scale + pub view_style: String, // original (default), scale #[serde(default)] pub image_quality: String, #[serde(default)] @@ -163,28 +159,28 @@ pub struct PeerInfoSerde { fn patch(path: PathBuf) -> PathBuf { if let Some(_tmp) = path.to_str() { #[cfg(windows)] - return _tmp + return _tmp .replace( "system32\\config\\systemprofile", "ServiceProfiles\\LocalService", ) .into(); #[cfg(target_os = "macos")] - return _tmp.replace("Application Support", "Preferences").into(); + return _tmp.replace("Application Support", "Preferences").into(); #[cfg(target_os = "linux")] - { - if _tmp == "/root" { - if let Ok(output) = std::process::Command::new("whoami").output() { - let user = String::from_utf8_lossy(&output.stdout) - .to_string() - .trim() - .to_owned(); - if user != "root" { - return format!("/home/{}", user).into(); - } + { + if _tmp == "/root" { + if let Ok(output) = std::process::Command::new("whoami").output() { + let user = String::from_utf8_lossy(&output.stdout) + .to_string() + .trim() + .to_owned(); + if user != "root" { + return format!("/home/{}", user).into(); } } } + } } path } @@ -194,11 +190,6 @@ impl Config2 { Config::load_::("2") } - fn reload(&mut self) { - let new_config = Config2::load(); - *self = new_config; - } - fn store(&self) { Config::store_(self, "2"); } @@ -238,11 +229,6 @@ impl Config { Config::store_(self, ""); } - fn reload(&mut self) { - let new_config = Config::load(); - *self = new_config; - } - pub fn file() -> PathBuf { Self::file_("") } @@ -276,7 +262,7 @@ impl Config { pub fn get_home() -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - return Self::path(""); + return Self::path(""); if let Some(path) = dirs_next::home_dir() { patch(path) } else if let Ok(path) = std::env::current_dir() { @@ -286,17 +272,17 @@ impl Config { } } - pub fn path>(p: P) -> PathBuf { + fn path>(p: P) -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - { - let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); - path.push(p); - return path; - } + { + let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); + path.push(p); + return path; + } #[cfg(not(target_os = "macos"))] - let org = ""; + let org = ""; #[cfg(target_os = "macos")] - let org = ORG; + let org = ORG; // /var/root for root if let Some(project) = ProjectDirs::from("", org, APP_NAME) { let mut path = patch(project.config_dir().to_path_buf()); @@ -309,19 +295,19 @@ impl Config { #[allow(unreachable_code)] pub fn log_path() -> PathBuf { #[cfg(target_os = "macos")] - { - if let Some(path) = dirs_next::home_dir().as_mut() { - path.push(format!("Library/Logs/{}", APP_NAME)); - return path.clone(); - } + { + if let Some(path) = dirs_next::home_dir().as_mut() { + path.push(format!("Library/Logs/{}", APP_NAME)); + return path.clone(); } + } #[cfg(target_os = "linux")] - { - let mut path = Self::get_home(); - path.push(format!(".local/share/logs/{}", APP_NAME)); - std::fs::create_dir_all(&path).ok(); - return path; - } + { + let mut path = Self::get_home(); + path.push(format!(".local/share/logs/{}", APP_NAME)); + std::fs::create_dir_all(&path).ok(); + return path; + } if let Some(path) = Self::path("").parent() { let mut path: PathBuf = path.into(); path.push("log"); @@ -332,21 +318,21 @@ impl Config { pub fn ipc_path(postfix: &str) -> String { #[cfg(windows)] - { - // \\ServerName\pipe\PipeName - // where ServerName is either the name of a remote computer or a period, to specify the local computer. - // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names - format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) - } + { + // \\ServerName\pipe\PipeName + // where ServerName is either the name of a remote computer or a period, to specify the local computer. + // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names + format!("\\\\.\\pipe\\{}\\query{}", APP_NAME, postfix) + } #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); - fs::create_dir(&path).ok(); - fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); - path.push(format!("ipc{}", postfix)); - path.to_str().unwrap_or("").to_owned() - } + { + use std::os::unix::fs::PermissionsExt; + let mut path: PathBuf = format!("/tmp/{}", APP_NAME).into(); + fs::create_dir(&path).ok(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok(); + path.push(format!("ipc{}", postfix)); + path.to_str().unwrap_or("").to_owned() + } } pub fn icon_path() -> PathBuf { @@ -460,7 +446,7 @@ impl Config { fn get_auto_id() -> Option { #[cfg(any(target_os = "android", target_os = "ios"))] - return None; + return None; let mut id = 0u32; #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Ok(Some(ma)) = mac_address::get_mac_address() { @@ -673,45 +659,6 @@ impl Config { Some(_) => NetworkType::ProxySocks, } } - - pub fn copy_and_reload_config_dir>( - target_username: String, - from: P, - ) -> Result { - let to = Self::path(""); - let to_parent = to.parent().unwrap(); - - let mut options = fs_extra::dir::CopyOptions::new(); - options.overwrite = true; - options.copy_inside = true; - - let mut f = from.as_ref(); - - return match fs_extra::dir::copy(f, to_parent, &options) { - Ok(count) => { - if count > 0 { - log::info!("{}",target_username); - log::info!("{}",f.to_str().unwrap().to_string()); - log::info!("{}",to.to_str().unwrap().to_string()); - - std::process::Command::new("chown") - .arg("-R") - .arg(target_username) - .arg(to.to_str().unwrap().to_string()) - .spawn(); - - CONFIG.write().unwrap().reload(); - CONFIG2.write().unwrap().reload(); - } - - Ok(count > 0) - } - Err(e) => { - log::error!("config copy failed: {}", e); - Err(e) - } - }; - } } const PEERS: &str = "peers"; @@ -810,7 +757,6 @@ impl Fav { #[cfg(test)] mod tests { use super::*; - #[test] fn test_serialize() { let cfg: Config = Default::default(); diff --git a/src/ipc.rs b/src/ipc.rs index bbfc40a31..e197d804d 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,10 +1,19 @@ -use hbb_common::{allow_err, bail, bytes, bytes_codec::BytesCodec, config::{self, Config}, futures::StreamExt as _, futures_util::sink::SinkExt, log, timeout, tokio, tokio::io::{AsyncRead, AsyncWrite}, tokio_util::codec::Framed, ResultType}; +use hbb_common::{ + allow_err, bail, bytes, + bytes_codec::BytesCodec, + config::{self, Config}, + futures::StreamExt as _, + futures_util::sink::SinkExt, + log, timeout, tokio, + tokio::io::{AsyncRead, AsyncWrite}, + tokio_util::codec::Framed, + ResultType, +}; use parity_tokio_ipc::{ Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes, }; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; -use std::path::PathBuf; #[cfg(not(windows))] use std::{fs::File, io::prelude::*}; @@ -83,11 +92,6 @@ pub enum Data { Socks(Option), FS(FS), Test, - ConfigCopyReq { - target_username: String, - dir_path: String, - }, - ConfigCopyResp(Option), } #[tokio::main(flavor = "current_thread")] @@ -125,7 +129,7 @@ pub async fn start(postfix: &str) -> ResultType<()> { pub async fn new_listener(postfix: &str) -> ResultType { let path = Config::ipc_path(postfix); #[cfg(not(windows))] - check_pid(postfix).await; + check_pid(postfix).await; let mut endpoint = Endpoint::new(path.clone()); match SecurityAttributes::allow_everyone_create() { Ok(attr) => endpoint.set_security_attributes(attr), @@ -135,11 +139,11 @@ pub async fn new_listener(postfix: &str) -> ResultType { Ok(incoming) => { log::info!("Started ipc{} server at path: {}", postfix, &path); #[cfg(not(windows))] - { - use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); - write_pid(postfix); - } + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o0777)).ok(); + write_pid(postfix); + } Ok(incoming) } Err(err) => { @@ -248,23 +252,6 @@ async fn handle(data: Data, stream: &mut Connection) { let t = Config::get_nat_type(); allow_err!(stream.send(&Data::NatType(Some(t))).await); } - Data::ConfigCopyReq { target_username, dir_path } => { - let from = PathBuf::from(dir_path); - if !from.exists() { - allow_err!(stream.send(&Data::ConfigCopyResp(None)).await); - return; - } - - match Config::copy_and_reload_config_dir(target_username, from) { - Ok(result) => { - allow_err!(stream.send(&Data::ConfigCopyResp(Some(result))).await); - } - Err(e) => { - log::error!("copy_and_reload_config_dir failed: {:?}",e); - allow_err!(stream.send(&Data::ConfigCopyResp(Some(false))).await); - } - } - } _ => {} } } @@ -325,8 +312,8 @@ pub struct ConnectionTmpl { pub type Connection = ConnectionTmpl; impl ConnectionTmpl - where - T: AsyncRead + AsyncWrite + std::marker::Unpin, +where + T: AsyncRead + AsyncWrite + std::marker::Unpin, { pub fn new(conn: T) -> Self { Self { diff --git a/src/lib.rs b/src/lib.rs index 7bac02eeb..2df657ab0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,4 +27,4 @@ use common::*; pub mod cli; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; -mod lang; \ No newline at end of file +mod lang; diff --git a/src/main.rs b/src/main.rs index 1af4c9f45..e2d00d0c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ fn main() { common::test_rendezvous_server(); common::test_nat_type(); #[cfg(target_os = "android")] - crate::common::check_software_update(); + crate::common::check_software_update(); mobile::Session::start(""); } @@ -29,53 +29,53 @@ fn main() { return; } #[cfg(not(feature = "inline"))] - { - use hbb_common::env_logger::*; - init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); - } + { + use hbb_common::env_logger::*; + init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); + } #[cfg(feature = "inline")] - { - let mut path = hbb_common::config::Config::log_path(); - if args.len() > 0 && args[0].starts_with("--") { - let name = args[0].replace("--", ""); - if !name.is_empty() { - path.push(name); - } + { + let mut path = hbb_common::config::Config::log_path(); + if args.len() > 0 && args[0].starts_with("--") { + let name = args[0].replace("--", ""); + if !name.is_empty() { + path.push(name); } - use flexi_logger::*; - Logger::try_with_env_or_str("debug") - .map(|x| { - x.log_to_file(FileSpec::default().directory(path)) - .format(opt_format) - .rotate( - Criterion::Age(Age::Day), - Naming::Timestamps, - Cleanup::KeepLogFiles(6), - ) - .start() - .ok(); - }) - .ok(); } + use flexi_logger::*; + Logger::try_with_env_or_str("debug") + .map(|x| { + x.log_to_file(FileSpec::default().directory(path)) + .format(opt_format) + .rotate( + Criterion::Age(Age::Day), + Naming::Timestamps, + Cleanup::KeepLogFiles(6), + ) + .start() + .ok(); + }) + .ok(); + } if args.is_empty() { std::thread::spawn(move || start_server(false, false)); } else { #[cfg(windows)] - { - if args[0] == "--uninstall" { - if let Err(err) = platform::uninstall_me() { - log::error!("Failed to uninstall: {}", err); - } - return; - } else if args[0] == "--update" { - hbb_common::allow_err!(platform::update_me()); - return; - } else if args[0] == "--reinstall" { - hbb_common::allow_err!(platform::uninstall_me()); - hbb_common::allow_err!(platform::install_me("desktopicon startmenu",)); - return; + { + if args[0] == "--uninstall" { + if let Err(err) = platform::uninstall_me() { + log::error!("Failed to uninstall: {}", err); } + return; + } else if args[0] == "--update" { + hbb_common::allow_err!(platform::update_me()); + return; + } else if args[0] == "--reinstall" { + hbb_common::allow_err!(platform::uninstall_me()); + hbb_common::allow_err!(platform::install_me("desktopicon startmenu",)); + return; } + } if args[0] == "--remove" { if args.len() == 2 { // sleep a while so that process of removed exe exit @@ -101,10 +101,6 @@ fn main() { ipc::set_password(args[1].to_owned()).unwrap(); } return; - } else if cfg!(target_os = "macos") && args[0] == "--daemon" { - log::info!("start --daemon"); - crate::platform::start_daemon(); - return; } } ui::start(&mut args[..]); diff --git a/src/platform/macos.rs b/src/platform/macos.rs index a79094172..5834fd024 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -333,10 +333,3 @@ pub fn block_input(_v: bool) { pub fn is_installed() -> bool { true } - -pub fn start_daemon(){ - if let Err(err) = crate::ipc::start("_daemon") { - log::error!("Failed to start ipc_daemon: {}", err); - std::process::exit(-1); - } -} diff --git a/src/server.rs b/src/server.rs index 27cf0061a..451c18e1b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use crate::ipc::{ConnectionTmpl, Data}; +use crate::ipc::Data; use connection::{ConnInner, Connection}; use hbb_common::{ allow_err, @@ -9,24 +9,18 @@ use hbb_common::{ message_proto::*, protobuf::{Message as _, ProtobufEnum}, rendezvous_proto::*, - sleep, socket_client, + sleep, sodiumoxide::crypto::{box_, secretbox, sign}, timeout, tokio, ResultType, Stream, + socket_client, }; use service::{GenericService, Service, ServiceTmpl, Subscriber}; -use std::sync::mpsc::RecvError; -use std::time::Duration; use std::{ collections::HashMap, net::SocketAddr, sync::{Arc, Mutex, RwLock, Weak}, }; -use hbb_common::log::info; -#[cfg(target_os = "macos")] -use notify::{watcher, RecursiveMode, Watcher}; -use parity_tokio_ipc::ConnectionClient; - mod audio_service; mod clipboard_service; mod connection; @@ -172,7 +166,7 @@ pub async fn create_relay_connection( secure: bool, ) { if let Err(err) = - create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await + create_relay_connection_(server, relay_server, uuid.clone(), peer_addr, secure).await { log::error!( "Failed to create relay connection for {} with uuid {}: {}", @@ -195,7 +189,7 @@ async fn create_relay_connection_( Config::get_any_listen_addr(), CONNECT_TIMEOUT, ) - .await?; + .await?; let mut msg_out = RendezvousMessage::new(); msg_out.set_request_relay(RequestRelay { uuid, @@ -270,13 +264,10 @@ pub fn check_zombie() { #[tokio::main] pub async fn start_server(is_server: bool, _tray: bool) { #[cfg(target_os = "linux")] - { - log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); - log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); - } - - sync_and_watch_config_dir().await; - + { + log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); + log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); + } if is_server { std::thread::spawn(move || { if let Err(err) = crate::ipc::start("") { @@ -307,7 +298,7 @@ pub async fn start_server(is_server: bool, _tray: bool) { } else { allow_err!(conn.send(&Data::ConfirmedKey(None)).await); if let Ok(Some(Data::ConfirmedKey(Some(pair)))) = - conn.next_timeout(1000).await + conn.next_timeout(1000).await { Config::set_key_pair(pair); Config::set_key_confirmed(true); @@ -326,72 +317,3 @@ pub async fn start_server(is_server: bool, _tray: bool) { } } } - -async fn sync_and_watch_config_dir() -> ResultType<()> { - let mut conn = crate::ipc::connect(1000, "_daemon").await?; - - sync_config_dir(&mut conn, "/var/root/Library/Preferences/com.carriez.RustDesk/".to_string()).await?; - - tokio::spawn(async move { - log::info!( - "watching config dir: {}", - Config::path("").to_str().unwrap().to_string() - ); - - let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); - watcher - .watch(Config::path("").as_path(), RecursiveMode::Recursive) - .unwrap(); - - loop { - let ev = rx.recv(); - match ev { - Ok(event) => match event { - notify::DebouncedEvent::Write(path) => { - log::info!( - "config file changed, call ipc_daemon to sync: {}", - path.to_str().unwrap().to_string() - ); - sync_config_dir(&mut conn, Config::path("").to_str().unwrap().to_string()).await; - } - x => { - log::info!("another {:?}", x) - } - }, - Err(e) => println!("watch error: {:?}", e), - } - } - }); - - Ok(()) -} - -async fn sync_config_dir(conn: &mut ConnectionTmpl, path: String) -> ResultType<()> { - allow_err!( - conn.send(&Data::ConfigCopyReq { - target_username: crate::username(), - dir_path: path - }) - .await - ); - if let Ok(Some(data)) = conn.next_timeout(1000).await { - match data { - Data::ConfigCopyResp(result) => match result { - Some(success) => { - if success { - log::info!("copy and reload config dir success"); - } else { - log::info!("copy config dir failed. may be first running"); - } - } - None => {} - }, - x => { - log::info!("receive another {:?}",x) - } - }; - }; - - Ok(()) -} From f45a2c7a94c9e2afa1bb67033d561bd497a9fca0 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 15:26:57 +0800 Subject: [PATCH 05/13] Add user and root config sync action --- Cargo.lock | 70 +++++++++++++++++++++ Cargo.toml | 1 + libs/hbb_common/src/config.rs | 99 ++++++++++++++++++++++++++++- src/ipc.rs | 27 ++++++++ src/main.rs | 4 ++ src/platform/macos.rs | 8 +++ src/server.rs | 114 +++++++++++++++++++++++++++++++++- 7 files changed, 319 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ea2e7c9b..435c226dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,6 +1115,25 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "fsevent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" +dependencies = [ + "bitflags", + "fsevent-sys", +] + +[[package]] +name = "fsevent-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +dependencies = [ + "libc", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1698,6 +1717,26 @@ dependencies = [ "tiff", ] +[[package]] +name = "inotify" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "instant" version = "0.1.12" @@ -2060,6 +2099,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio 0.6.23", + "slab", +] + [[package]] name = "mio-named-pipes" version = "0.1.7" @@ -2224,6 +2275,24 @@ dependencies = [ "version_check", ] +[[package]] +name = "notify" +version = "4.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +dependencies = [ + "bitflags", + "filetime", + "fsevent", + "fsevent-sys", + "inotify", + "libc", + "mio 0.6.23", + "mio-extras", + "walkdir", + "winapi 0.3.9", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -3153,6 +3222,7 @@ dependencies = [ "mac_address", "machine-uid", "magnum-opus", + "notify", "objc", "parity-tokio-ipc", "psutil", diff --git a/Cargo.toml b/Cargo.toml index 6a9325e25..9a13bedaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ cocoa = "0.24" dispatch = "0.2" core-foundation = "0.9" core-graphics = "0.22" +notify = "4.0.17" [target.'cfg(target_os = "linux")'.dependencies] libpulse-simple-binding = "2.24" diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 21ca74a06..85dcfd984 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -190,6 +190,11 @@ impl Config2 { Config::load_::("2") } + fn reload(&mut self) { + let new_config = Config2::load(); + *self = new_config; + } + fn store(&self) { Config::store_(self, "2"); } @@ -214,6 +219,11 @@ impl Config { cfg } + fn reload(&mut self) { + let new_config = Config::load(); + *self = new_config; + } + fn store_(config: &T, suffix: &str) { let file = Self::file_(suffix); if let Err(err) = confy::store_path(file, config) { @@ -272,7 +282,7 @@ impl Config { } } - fn path>(p: P) -> PathBuf { + pub fn path>(p: P) -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] { let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); @@ -659,6 +669,93 @@ impl Config { Some(_) => NetworkType::ProxySocks, } } + + pub fn sync_config_to_user>(target_username: String, to_dir: P) -> bool { + let config1_root_file_path = Config::file_(""); + let config1_filename = config1_root_file_path.file_name(); + + let config2_root_file_path = Config::file_("2"); + let config2_filename = config2_root_file_path.file_name(); + + let config1_to_file_path = to_dir + .as_ref() + .join(PathBuf::from(&config1_filename.unwrap())); + let config2_to_file_path = to_dir + .as_ref() + .join(PathBuf::from(&config2_filename.unwrap())); + + log::info!( + "config1_root_path:{}", + &config1_root_file_path.as_path().to_str().unwrap() + ); + log::info!( + "config2_root_path:{}", + &config2_root_file_path.as_path().to_str().unwrap() + ); + log::info!( + "config1_to_path:{}", + &config1_to_file_path.as_path().to_str().unwrap() + ); + log::info!( + "config2_to_path:{}", + &config2_to_file_path.as_path().to_str().unwrap() + ); + + match std::fs::copy(&config1_root_file_path, &config1_to_file_path) { + Err(e) => log::error!( + "copy config {} to user failed: {}", + config1_filename.unwrap().to_str().unwrap(), + e + ), + _ => {} + } + + match std::fs::copy(&config2_root_file_path, &config2_to_file_path) { + Err(e) => log::error!( + "copy config {} to user failed: {}", + config2_filename.unwrap().to_str().unwrap(), + e + ), + _ => {} + } + + let success = std::process::Command::new("chown") + .arg(&target_username.to_string()) + .arg(&config1_to_file_path.to_str().unwrap().to_string()) + .arg(&config2_to_file_path.to_str().unwrap().to_string()) + .spawn() + .is_ok(); + + if success { + CONFIG.write().unwrap().reload(); + CONFIG2.write().unwrap().reload(); + } + + return success; + } + + pub fn sync_config_to_root>(from_file_path: P) -> bool { + if let Some(filename) = from_file_path.as_ref().file_name() { + let to = Config::path(filename); + return match std::fs::copy(from_file_path, &to) { + Ok(count) => { + if count > 0 { + return std::process::Command::new("chown") + .arg("root") + .arg(&to.to_str().unwrap().to_string()) + .spawn() + .is_ok(); + } + false + } + Err(e) => { + log::error!("sync_config_to_root failed: {}", e); + false + } + }; + } + false + } } const PEERS: &str = "peers"; diff --git a/src/ipc.rs b/src/ipc.rs index e197d804d..8bd206f67 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -92,6 +92,15 @@ pub enum Data { Socks(Option), FS(FS), Test, + SyncConfigToRootReq { + from: String, + }, + SyncConfigToRootResp(bool), + SyncConfigToUserReq { + username: String, + to: String, + }, + SyncConfigToUserResp(bool), } #[tokio::main(flavor = "current_thread")] @@ -252,6 +261,24 @@ async fn handle(data: Data, stream: &mut Connection) { let t = Config::get_nat_type(); allow_err!(stream.send(&Data::NatType(Some(t))).await); } + Data::SyncConfigToRootReq { from } => { + allow_err!( + stream + .send(&Data::SyncConfigToRootResp(Config::sync_config_to_root( + from + ))) + .await + ); + } + Data::SyncConfigToUserReq { username, to } => { + allow_err!( + stream + .send(&Data::SyncConfigToUserResp(Config::sync_config_to_user( + username, to + ))) + .await + ); + } _ => {} } } diff --git a/src/main.rs b/src/main.rs index e2d00d0c5..39b52cb58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,6 +101,10 @@ fn main() { ipc::set_password(args[1].to_owned()).unwrap(); } return; + } else if cfg!(target_os = "macos") && args[0] == "--daemon" { + log::info!("start --daemon"); + crate::platform::start_daemon(); + return; } } ui::start(&mut args[..]); diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 5834fd024..f278fdf9c 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -333,3 +333,11 @@ pub fn block_input(_v: bool) { pub fn is_installed() -> bool { true } + +pub fn start_daemon(){ + log::info!("{}",crate::username()); + if let Err(err) = crate::ipc::start("_daemon") { + log::error!("Failed to start ipc_daemon: {}", err); + std::process::exit(-1); + } +} diff --git a/src/server.rs b/src/server.rs index 451c18e1b..13e3a678d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use crate::ipc::Data; +use crate::ipc::{ConnectionTmpl, Data}; use connection::{ConnInner, Connection}; use hbb_common::{ allow_err, @@ -9,12 +9,15 @@ use hbb_common::{ message_proto::*, protobuf::{Message as _, ProtobufEnum}, rendezvous_proto::*, - sleep, + sleep, socket_client, sodiumoxide::crypto::{box_, secretbox, sign}, timeout, tokio, ResultType, Stream, - socket_client, }; +use notify::{watcher, RecursiveMode, Watcher}; +use parity_tokio_ipc::ConnectionClient; use service::{GenericService, Service, ServiceTmpl, Subscriber}; +use std::path::PathBuf; +use std::time::Duration; use std::{ collections::HashMap, net::SocketAddr, @@ -268,6 +271,9 @@ pub async fn start_server(is_server: bool, _tray: bool) { log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); } + + sync_and_watch_config_dir().await; + if is_server { std::thread::spawn(move || { if let Err(err) = crate::ipc::start("") { @@ -317,3 +323,105 @@ pub async fn start_server(is_server: bool, _tray: bool) { } } } + +async fn sync_and_watch_config_dir() { + if crate::username() == "root" { + return; + } + + match crate::ipc::connect(1000, "_daemon").await { + Ok(mut conn) => { + match sync_config_to_user(&mut conn).await { + Err(e) => log::error!("sync config to user failed:{}", e), + _ => {} + } + + tokio::spawn(async move { + log::info!( + "watching config dir: {}", + Config::path("").to_str().unwrap().to_string() + ); + + let (tx, rx) = std::sync::mpsc::channel(); + let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); + watcher + .watch(Config::path("").as_path(), RecursiveMode::Recursive) + .unwrap(); + + loop { + let ev = rx.recv(); + match ev { + Ok(event) => match event { + notify::DebouncedEvent::Write(path) => { + log::info!( + "config file changed, call ipc_daemon to sync: {}", + path.to_str().unwrap().to_string() + ); + + match sync_config_to_root(&mut conn, path).await { + Err(e) => log::error!("sync config to root failed: {}", e), + _ => {} + } + } + x => { + log::debug!("another {:?}", x) + } + }, + Err(e) => println!("watch error: {:?}", e), + } + } + }); + } + Err(_) => { + log::info!("connect ipc_daemon failed, skip config sync"); + return; + } + } +} + +async fn sync_config_to_user(conn: &mut ConnectionTmpl) -> ResultType<()> { + allow_err!( + conn.send(&Data::SyncConfigToUserReq { + username: crate::username(), + to: Config::path("").to_str().unwrap().to_string(), + }) + .await + ); + + if let Some(data) = conn.next_timeout(2000).await? { + match data { + Data::SyncConfigToUserResp(success) => { + log::info!("copy and reload config dir success: {:?}", success); + } + _ => {} + }; + }; + + Ok(()) +} + +async fn sync_config_to_root( + conn: &mut ConnectionTmpl, + from: PathBuf, +) -> ResultType<()> { + allow_err!( + conn.send(&Data::SyncConfigToRootReq { + from: from.to_str().unwrap().to_string() + }) + .await + ); + + // todo: this code will block outer loop, resolve it later. + // if let Some(data) = conn.next_timeout(2000).await? { + // match data { + // Data::SyncConfigToRootResp(success) => { + // log::info!("copy config to root dir success: {:?}", success); + // } + // x => { + // log::info!("receive another {:?}", x) + // } + // }; + // }; + + Ok(()) +} From 9be6b17a8bf07e4756a1c03b6b4eba865134cd5d Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 19:23:41 +0800 Subject: [PATCH 06/13] Add launch service --- .../com.carriez.rustdesk.agent.root.plist | 30 ++++++++++ .../com.carriez.rustdesk.agent.user.plist | 30 ++++++++++ .../com.carriez.rustdesk.daemon.plist | 23 ++++++++ privileges_scripts/install.scpt | 9 +++ privileges_scripts/launch_service.scpt | 10 ++++ privileges_scripts/stop_service.scpt | 10 ++++ src/platform/macos.rs | 56 ++++++++++++++++++- src/ui.rs | 22 ++++++++ src/ui/index.tis | 16 ++++++ 9 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 privileges_scripts/com.carriez.rustdesk.agent.root.plist create mode 100644 privileges_scripts/com.carriez.rustdesk.agent.user.plist create mode 100644 privileges_scripts/com.carriez.rustdesk.daemon.plist create mode 100644 privileges_scripts/install.scpt create mode 100644 privileges_scripts/launch_service.scpt create mode 100644 privileges_scripts/stop_service.scpt diff --git a/privileges_scripts/com.carriez.rustdesk.agent.root.plist b/privileges_scripts/com.carriez.rustdesk.agent.root.plist new file mode 100644 index 000000000..72dbe816e --- /dev/null +++ b/privileges_scripts/com.carriez.rustdesk.agent.root.plist @@ -0,0 +1,30 @@ + + + + + Disable + + Label + com.carriez.rustdesk.agent.root + LimitLoadToSessionType + + LoginWindow + + KeepAlive + + SuccessfulExit + + AfterInitialDemand + + + RunAtLoad + + ProgramArguments + + /Applications/RustDesk.app/Contents/MacOS/rustdesk + --server + + WorkingDirectory + /Applications/RustDesk.app/Contents/MacOS/ + + \ No newline at end of file diff --git a/privileges_scripts/com.carriez.rustdesk.agent.user.plist b/privileges_scripts/com.carriez.rustdesk.agent.user.plist new file mode 100644 index 000000000..1e24769d4 --- /dev/null +++ b/privileges_scripts/com.carriez.rustdesk.agent.user.plist @@ -0,0 +1,30 @@ + + + + + Disable + + Label + com.carriez.rustdesk.agent.root + LimitLoadToSessionType + + Aqua + + KeepAlive + + SuccessfulExit + + AfterInitialDemand + + + RunAtLoad + + ProgramArguments + + /Applications/RustDesk.app/Contents/MacOS/rustdesk + --server + + WorkingDirectory + /Applications/RustDesk.app/Contents/MacOS/ + + \ No newline at end of file diff --git a/privileges_scripts/com.carriez.rustdesk.daemon.plist b/privileges_scripts/com.carriez.rustdesk.daemon.plist new file mode 100644 index 000000000..8d4d1b106 --- /dev/null +++ b/privileges_scripts/com.carriez.rustdesk.daemon.plist @@ -0,0 +1,23 @@ + + + + + Label + com.carriez.rustdesk.daemon + Disabled + + KeepAlive + + Label + com.youqu.todesk.service + ProgramArguments + + /Applications/RustDesk.app/Contents/MacOS/rustdesk + --daemon + + RunAtLoad + + WorkingDirectory + /Applications/RustDesk.app/Contents/MacOS/ + + \ No newline at end of file diff --git a/privileges_scripts/install.scpt b/privileges_scripts/install.scpt new file mode 100644 index 000000000..84937050f --- /dev/null +++ b/privileges_scripts/install.scpt @@ -0,0 +1,9 @@ +set current_dir to POSIX path of ((path to me as text) & "::") + +set sh1 to "cp " & current_dir & "com.carriez.rustdesk.daemon.plist /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist" +set sh2 to "cp " & current_dir & "com.carriez.rustdesk.agent.root.plist /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist" +set sh3 to "cp " & current_dir & "com.carriez.rustdesk.agent.user.plist /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist" + +set sh to sh1 & ";" & sh2 & ";" & sh3 + +do shell script sh with prompt "RustDesk需要安装服务plist" with administrator privileges \ No newline at end of file diff --git a/privileges_scripts/launch_service.scpt b/privileges_scripts/launch_service.scpt new file mode 100644 index 000000000..f0ef31408 --- /dev/null +++ b/privileges_scripts/launch_service.scpt @@ -0,0 +1,10 @@ +set sh to " +launchctl enable system/com.carriez.rustdesk.daemon; +launchctl start system/com.carriez.rustdesk.daemon; +launchctl enable system/com.carriez.rustdesk.agent.root; +launchctl start system/com.carriez.rustdesk.agent.root; +launchctl enable system/com.carriez.rustdesk.agent.user +launchctl start system/com.carriez.rustdesk.agent.user +" + +do shell script sh with prompt "RustDesk需要启动服务" with administrator privileges \ No newline at end of file diff --git a/privileges_scripts/stop_service.scpt b/privileges_scripts/stop_service.scpt new file mode 100644 index 000000000..9a60ec899 --- /dev/null +++ b/privileges_scripts/stop_service.scpt @@ -0,0 +1,10 @@ +set sh to " +launchctl disable system/com.carriez.rustdesk.daemon; +launchctl stop system/com.carriez.rustdesk.daemon; +launchctl disable system/com.carriez.rustdesk.agent.root; +launchctl stop system/com.carriez.rustdesk.agent.root; +launchctl disable system/com.carriez.rustdesk.agent.user +launchctl stop system/com.carriez.rustdesk.agent.user +" + +do shell script sh with prompt "RustDesk需要停止服务" with administrator privileges \ No newline at end of file diff --git a/src/platform/macos.rs b/src/platform/macos.rs index f278fdf9c..85b3e8ea1 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -19,6 +19,7 @@ use core_graphics::{ use hbb_common::{allow_err, bail, log}; use objc::{class, msg_send, sel, sel_impl}; use scrap::{libc::c_void, quartz::ffi::*}; +use std::io::Read; static mut LATEST_SEED: i32 = 0; @@ -98,6 +99,57 @@ pub fn is_can_screen_recording(prompt: bool) -> bool { can_record_screen } +pub fn is_installed_daemon(prompt: bool) -> bool { + if !prompt { + let output = std::process::Command::new("launchctl") + .args(vec!["list", "|", "grep", "com.carriez.rustdesk.daemon"]) + .stdout(std::process::Stdio::piped()) + .output() + .unwrap(); + if output.stdout.len() <= 0{ + return false; + } + + let output = std::process::Command::new("launchctl") + .args(vec!["list", "|", "grep", "com.carriez.rustdesk.agent.root"]) + .stdout(std::process::Stdio::piped()) + .output() + .unwrap(); + if output.stdout.len() <= 0{ + return false; + } + + let output = std::process::Command::new("launchctl") + .args(vec!["list", "|", "grep", "com.carriez.rustdesk.agent.user"]) + .stdout(std::process::Stdio::piped()) + .output() + .unwrap(); + if output.stdout.len() <= 0{ + return false; + } + + return true; + } + + if !std::process::Command::new("osascript") + .arg("./privileges_scripts/install.scpt") + .status() + .unwrap() + .success() { + return false; + } + + if !std::process::Command::new("osascript") + .arg("./privileges_scripts/launch_service.scpt") + .status() + .unwrap() + .success() { + return false; + } + + return true; +} + pub fn get_cursor_pos() -> Option<(i32, i32)> { unsafe { let e = CGEventCreate(0 as _); @@ -334,8 +386,8 @@ pub fn is_installed() -> bool { true } -pub fn start_daemon(){ - log::info!("{}",crate::username()); +pub fn start_daemon() { + log::info!("{}", crate::username()); if let Err(err) = crate::ipc::start("_daemon") { log::error!("Failed to start ipc_daemon: {}", err); std::process::exit(-1); diff --git a/src/ui.rs b/src/ui.rs index 7255c47b7..f12b6dcc5 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -363,6 +363,20 @@ impl UI { options.insert(key, value); } ipc::set_options(options.clone()).ok(); + + #[cfg(macos)] + if key == "stop-service" { + let mut service_script = "./privileges_scripts/stop_service.scpt"; + if value == "Y" { + command = "./privileges_scripts/launch_service.scpt"; + } + + std::process::Command::new("osascript") + .arg(service_script) + .status() + .unwrap() + .success(); + } } fn install_path(&mut self) -> String { @@ -525,6 +539,13 @@ impl UI { return true; } + fn is_installed_daemon(&mut self, _prompt: bool) -> bool { + #[cfg(target_os = "macos")] + return crate::platform::macos::is_installed_daemon(_prompt); + #[cfg(not(target_os = "macos"))] + return true; + } + fn get_error(&mut self) -> String { #[cfg(target_os = "linux")] { @@ -668,6 +689,7 @@ impl sciter::EventHandler for UI { fn goto_install(); fn is_process_trusted(bool); fn is_can_screen_recording(bool); + fn is_installed_daemon(bool); fn get_error(); fn is_login_wayland(); fn fix_login_wayland(); diff --git a/src/ui/index.tis b/src/ui/index.tis index a69e5b014..850a35e62 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -307,6 +307,7 @@ class App: Reactor.Component {handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? : ""} {is_can_screen_recording ? "": } {is_can_screen_recording && !handler.is_process_trusted(false) ? : ""} + {is_can_screen_recording && handler.is_process_trusted(false) && handler.is_installed_daemon(false) ? : ""} {system_error ? : ""} {!system_error && handler.is_login_wayland() && !handler.current_is_wayland() ? : ""} {!system_error && handler.current_is_wayland() ? : ""} @@ -491,6 +492,21 @@ class CanScreenRecording: Reactor.Component { } } +class InstallDaemon: Reactor.Component { + function render() { + return
+
{translate('Configuration Permissions')}
+
{translate('install_daemon')}
+
{translate('Configure')}
+
; + } + + event click $(#install-daemon) { + handler.is_installed_daemon(true); + watch_trust(); + } +} + class FixWayland: Reactor.Component { function render() { return
From 8e6dd76c5bcb1a669818ac90460f49028fe82aa2 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 19:42:25 +0800 Subject: [PATCH 07/13] remove unused import and launch service when install --- privileges_scripts/install.scpt | 11 +++++++++-- src/lang/cn.rs | 1 + src/platform/macos.rs | 9 --------- src/ui/index.tis | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/privileges_scripts/install.scpt b/privileges_scripts/install.scpt index 84937050f..e1dd2464d 100644 --- a/privileges_scripts/install.scpt +++ b/privileges_scripts/install.scpt @@ -4,6 +4,13 @@ set sh1 to "cp " & current_dir & "com.carriez.rustdesk.daemon.plist /Library/Lau set sh2 to "cp " & current_dir & "com.carriez.rustdesk.agent.root.plist /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist" set sh3 to "cp " & current_dir & "com.carriez.rustdesk.agent.user.plist /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist" -set sh to sh1 & ";" & sh2 & ";" & sh3 +set sh to sh1 & ";" & sh2 & ";" & sh3 & " +launchctl enable system/com.carriez.rustdesk.daemon; +launchctl start system/com.carriez.rustdesk.daemon; +launchctl enable system/com.carriez.rustdesk.agent.root; +launchctl start system/com.carriez.rustdesk.agent.root; +launchctl enable system/com.carriez.rustdesk.agent.user +launchctl start system/com.carriez.rustdesk.agent.user +" -do shell script sh with prompt "RustDesk需要安装服务plist" with administrator privileges \ No newline at end of file +do shell script sh with prompt "RustDesk需要安装服务" with administrator privileges \ No newline at end of file diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 23dd4348c..98d645063 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -195,5 +195,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Socks5 Proxy", "Socks5 代理"), ("Hostname", "主机名"), ("Discovered", "已发现"), + ("install_daemon", "为了支持在登录系统时可以访问你的桌面,RustDesk需要\"安装系统服务\"") ].iter().cloned().collect(); } diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 85b3e8ea1..7b9720c6e 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -19,7 +19,6 @@ use core_graphics::{ use hbb_common::{allow_err, bail, log}; use objc::{class, msg_send, sel, sel_impl}; use scrap::{libc::c_void, quartz::ffi::*}; -use std::io::Read; static mut LATEST_SEED: i32 = 0; @@ -139,14 +138,6 @@ pub fn is_installed_daemon(prompt: bool) -> bool { return false; } - if !std::process::Command::new("osascript") - .arg("./privileges_scripts/launch_service.scpt") - .status() - .unwrap() - .success() { - return false; - } - return true; } diff --git a/src/ui/index.tis b/src/ui/index.tis index 850a35e62..d58497b3d 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -307,7 +307,7 @@ class App: Reactor.Component {handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? : ""} {is_can_screen_recording ? "": } {is_can_screen_recording && !handler.is_process_trusted(false) ? : ""} - {is_can_screen_recording && handler.is_process_trusted(false) && handler.is_installed_daemon(false) ? : ""} + {is_can_screen_recording && handler.is_process_trusted(false) && !handler.is_installed_daemon(false) ? : ""} {system_error ? : ""} {!system_error && handler.is_login_wayland() && !handler.current_is_wayland() ? : ""} {!system_error && handler.current_is_wayland() ? : ""} From 29bb10a40a404a2c5d90912ca28ced3968c614db Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Thu, 13 Jan 2022 20:34:28 +0800 Subject: [PATCH 08/13] modify daemon install check --- src/platform/macos.rs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 7b9720c6e..701f185df 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -100,30 +100,16 @@ pub fn is_can_screen_recording(prompt: bool) -> bool { pub fn is_installed_daemon(prompt: bool) -> bool { if !prompt { - let output = std::process::Command::new("launchctl") - .args(vec!["list", "|", "grep", "com.carriez.rustdesk.daemon"]) - .stdout(std::process::Stdio::piped()) - .output() - .unwrap(); - if output.stdout.len() <= 0{ + + if !std::path::Path::new("/Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist").exists(){ return false; } - let output = std::process::Command::new("launchctl") - .args(vec!["list", "|", "grep", "com.carriez.rustdesk.agent.root"]) - .stdout(std::process::Stdio::piped()) - .output() - .unwrap(); - if output.stdout.len() <= 0{ + if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist").exists(){ return false; } - let output = std::process::Command::new("launchctl") - .args(vec!["list", "|", "grep", "com.carriez.rustdesk.agent.user"]) - .stdout(std::process::Stdio::piped()) - .output() - .unwrap(); - if output.stdout.len() <= 0{ + if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist").exists(){ return false; } From b4f61c735ef6246eebda773954ef8ac0528897c2 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Fri, 14 Jan 2022 03:17:36 +0800 Subject: [PATCH 09/13] fix plist files and enhance privilege escalation method --- Cargo.lock | 20 ++++++ Cargo.toml | 2 +- privileges_scripts/install.scpt | 16 ----- privileges_scripts/launch_service.scpt | 10 --- privileges_scripts/stop_service.scpt | 10 --- src/lang/cn.rs | 1 - src/platform/macos.rs | 69 ++++++++++++++++--- .../com.carriez.rustdesk.agent.root.plist | 2 - .../com.carriez.rustdesk.agent.user.plist | 4 +- .../com.carriez.rustdesk.daemon.plist | 4 -- src/platform/privileges_scripts/install.scpt | 19 +++++ .../privileges_scripts/launch_service.scpt | 7 ++ .../privileges_scripts/stop_service.scpt | 7 ++ src/ui.rs | 16 +---- 14 files changed, 116 insertions(+), 71 deletions(-) delete mode 100644 privileges_scripts/install.scpt delete mode 100644 privileges_scripts/launch_service.scpt delete mode 100644 privileges_scripts/stop_service.scpt rename {privileges_scripts => src/platform/privileges_scripts}/com.carriez.rustdesk.agent.root.plist (95%) rename {privileges_scripts => src/platform/privileges_scripts}/com.carriez.rustdesk.agent.user.plist (89%) rename {privileges_scripts => src/platform/privileges_scripts}/com.carriez.rustdesk.daemon.plist (84%) create mode 100644 src/platform/privileges_scripts/install.scpt create mode 100644 src/platform/privileges_scripts/launch_service.scpt create mode 100644 src/platform/privileges_scripts/stop_service.scpt diff --git a/Cargo.lock b/Cargo.lock index 435c226dc..74f841f90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1717,6 +1717,25 @@ dependencies = [ "tiff", ] +[[package]] +name = "include_dir" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482a2e29200b7eed25d7fdbd14423326760b7f6658d21a4cf12d55a50713c69f" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e074c19deab2501407c91ba1860fa3d6820bfde307db6d8cb851b55a10be89b" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "inotify" version = "0.7.1" @@ -3215,6 +3234,7 @@ dependencies = [ "flexi_logger", "hbb_common", "hound", + "include_dir", "lazy_static", "libc", "libpulse-binding", diff --git a/Cargo.toml b/Cargo.toml index 9a13bedaf..4f10ec7d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ dispatch = "0.2" core-foundation = "0.9" core-graphics = "0.22" notify = "4.0.17" - +include_dir = "0.7.2" [target.'cfg(target_os = "linux")'.dependencies] libpulse-simple-binding = "2.24" libpulse-binding = "2.25" diff --git a/privileges_scripts/install.scpt b/privileges_scripts/install.scpt deleted file mode 100644 index e1dd2464d..000000000 --- a/privileges_scripts/install.scpt +++ /dev/null @@ -1,16 +0,0 @@ -set current_dir to POSIX path of ((path to me as text) & "::") - -set sh1 to "cp " & current_dir & "com.carriez.rustdesk.daemon.plist /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist" -set sh2 to "cp " & current_dir & "com.carriez.rustdesk.agent.root.plist /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist" -set sh3 to "cp " & current_dir & "com.carriez.rustdesk.agent.user.plist /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist" - -set sh to sh1 & ";" & sh2 & ";" & sh3 & " -launchctl enable system/com.carriez.rustdesk.daemon; -launchctl start system/com.carriez.rustdesk.daemon; -launchctl enable system/com.carriez.rustdesk.agent.root; -launchctl start system/com.carriez.rustdesk.agent.root; -launchctl enable system/com.carriez.rustdesk.agent.user -launchctl start system/com.carriez.rustdesk.agent.user -" - -do shell script sh with prompt "RustDesk需要安装服务" with administrator privileges \ No newline at end of file diff --git a/privileges_scripts/launch_service.scpt b/privileges_scripts/launch_service.scpt deleted file mode 100644 index f0ef31408..000000000 --- a/privileges_scripts/launch_service.scpt +++ /dev/null @@ -1,10 +0,0 @@ -set sh to " -launchctl enable system/com.carriez.rustdesk.daemon; -launchctl start system/com.carriez.rustdesk.daemon; -launchctl enable system/com.carriez.rustdesk.agent.root; -launchctl start system/com.carriez.rustdesk.agent.root; -launchctl enable system/com.carriez.rustdesk.agent.user -launchctl start system/com.carriez.rustdesk.agent.user -" - -do shell script sh with prompt "RustDesk需要启动服务" with administrator privileges \ No newline at end of file diff --git a/privileges_scripts/stop_service.scpt b/privileges_scripts/stop_service.scpt deleted file mode 100644 index 9a60ec899..000000000 --- a/privileges_scripts/stop_service.scpt +++ /dev/null @@ -1,10 +0,0 @@ -set sh to " -launchctl disable system/com.carriez.rustdesk.daemon; -launchctl stop system/com.carriez.rustdesk.daemon; -launchctl disable system/com.carriez.rustdesk.agent.root; -launchctl stop system/com.carriez.rustdesk.agent.root; -launchctl disable system/com.carriez.rustdesk.agent.user -launchctl stop system/com.carriez.rustdesk.agent.user -" - -do shell script sh with prompt "RustDesk需要停止服务" with administrator privileges \ No newline at end of file diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 98d645063..23dd4348c 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -195,6 +195,5 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Socks5 Proxy", "Socks5 代理"), ("Hostname", "主机名"), ("Discovered", "已发现"), - ("install_daemon", "为了支持在登录系统时可以访问你的桌面,RustDesk需要\"安装系统服务\"") ].iter().cloned().collect(); } diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 701f185df..92369d258 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -17,9 +17,12 @@ use core_graphics::{ window::{kCGWindowName, kCGWindowOwnerPID}, }; use hbb_common::{allow_err, bail, log}; +use include_dir::{include_dir, Dir}; use objc::{class, msg_send, sel, sel_impl}; use scrap::{libc::c_void, quartz::ffi::*}; +static PRIVILEGES_SCRIPTS_DIR: Dir = + include_dir!("$CARGO_MANIFEST_DIR/src/platform/privileges_scripts"); static mut LATEST_SEED: i32 = 0; extern "C" { @@ -100,31 +103,75 @@ pub fn is_can_screen_recording(prompt: bool) -> bool { pub fn is_installed_daemon(prompt: bool) -> bool { if !prompt { - - if !std::path::Path::new("/Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist").exists(){ + if !std::path::Path::new("/Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist") + .exists() + { return false; } - if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist").exists(){ + if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist") + .exists() + { return false; } - if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist").exists(){ + if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist") + .exists() + { return false; } return true; } - if !std::process::Command::new("osascript") - .arg("./privileges_scripts/install.scpt") - .status() - .unwrap() - .success() { - return false; + let install_script = PRIVILEGES_SCRIPTS_DIR.get_file("install.scpt").unwrap(); + let install_script_body = install_script.contents_utf8().unwrap(); + + let daemon_plist = PRIVILEGES_SCRIPTS_DIR + .get_file("com.carriez.rustdesk.daemon.plist") + .unwrap(); + let daemon_plist_body = daemon_plist.contents_utf8().unwrap(); + + let root_agent_plist = PRIVILEGES_SCRIPTS_DIR + .get_file("com.carriez.rustdesk.agent.root.plist") + .unwrap(); + let root_agent_plist_body = root_agent_plist.contents_utf8().unwrap(); + + let user_agent_plist = PRIVILEGES_SCRIPTS_DIR + .get_file("com.carriez.rustdesk.agent.user.plist") + .unwrap(); + let user_agent_plist_body = user_agent_plist.contents_utf8().unwrap(); + + match std::process::Command::new("osascript") + .arg("-e") + .arg(install_script_body) + .arg(daemon_plist_body) + .arg(root_agent_plist_body) + .arg(user_agent_plist_body) + .spawn() + { + Ok(mut proc) => proc.wait().is_ok(), + Err(e) => { + log::error!("run osascript failed: {}", e); + false + }, + } +} + +pub fn launch_or_stop_daemon(launch: bool) { + let mut script_filename = "launch_service.scpt"; + if !launch { + script_filename = "stop_service.scpt"; } - return true; + let script_file = PRIVILEGES_SCRIPTS_DIR.get_file(script_filename).unwrap(); + let script_body = script_file.contents_utf8().unwrap(); + + std::process::Command::new("osascript") + .arg("-e") + .arg(script_body) + .spawn() + .ok(); } pub fn get_cursor_pos() -> Option<(i32, i32)> { diff --git a/privileges_scripts/com.carriez.rustdesk.agent.root.plist b/src/platform/privileges_scripts/com.carriez.rustdesk.agent.root.plist similarity index 95% rename from privileges_scripts/com.carriez.rustdesk.agent.root.plist rename to src/platform/privileges_scripts/com.carriez.rustdesk.agent.root.plist index 72dbe816e..b77a31f54 100644 --- a/privileges_scripts/com.carriez.rustdesk.agent.root.plist +++ b/src/platform/privileges_scripts/com.carriez.rustdesk.agent.root.plist @@ -2,8 +2,6 @@ - Disable - Label com.carriez.rustdesk.agent.root LimitLoadToSessionType diff --git a/privileges_scripts/com.carriez.rustdesk.agent.user.plist b/src/platform/privileges_scripts/com.carriez.rustdesk.agent.user.plist similarity index 89% rename from privileges_scripts/com.carriez.rustdesk.agent.user.plist rename to src/platform/privileges_scripts/com.carriez.rustdesk.agent.user.plist index 1e24769d4..fc13fa1f5 100644 --- a/privileges_scripts/com.carriez.rustdesk.agent.user.plist +++ b/src/platform/privileges_scripts/com.carriez.rustdesk.agent.user.plist @@ -2,10 +2,8 @@ - Disable - Label - com.carriez.rustdesk.agent.root + com.carriez.rustdesk.agent.user LimitLoadToSessionType Aqua diff --git a/privileges_scripts/com.carriez.rustdesk.daemon.plist b/src/platform/privileges_scripts/com.carriez.rustdesk.daemon.plist similarity index 84% rename from privileges_scripts/com.carriez.rustdesk.daemon.plist rename to src/platform/privileges_scripts/com.carriez.rustdesk.daemon.plist index 8d4d1b106..529af8c5a 100644 --- a/privileges_scripts/com.carriez.rustdesk.daemon.plist +++ b/src/platform/privileges_scripts/com.carriez.rustdesk.daemon.plist @@ -4,12 +4,8 @@ Label com.carriez.rustdesk.daemon - Disabled - KeepAlive - Label - com.youqu.todesk.service ProgramArguments /Applications/RustDesk.app/Contents/MacOS/rustdesk diff --git a/src/platform/privileges_scripts/install.scpt b/src/platform/privileges_scripts/install.scpt new file mode 100644 index 000000000..9d96fa9de --- /dev/null +++ b/src/platform/privileges_scripts/install.scpt @@ -0,0 +1,19 @@ +on run {daemon_file, root_agent_file, user_agent_file} + + set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist;" + + set sh2 to "echo " & quoted form of root_agent_file & " > /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" + + set sh3 to "echo " & quoted form of user_agent_file & " > /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" + + set sh4 to "launchctl load -w /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist;" + + set sh5 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" + + set sh6 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" + + set sh to sh1 & sh2 & sh3 & sh4 & sh5 &sh6 + + log (sh) + do shell script sh with prompt "RustDesk 需要安装服务" with administrator privileges +end run \ No newline at end of file diff --git a/src/platform/privileges_scripts/launch_service.scpt b/src/platform/privileges_scripts/launch_service.scpt new file mode 100644 index 000000000..3a0b530b0 --- /dev/null +++ b/src/platform/privileges_scripts/launch_service.scpt @@ -0,0 +1,7 @@ +set sh1 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" + +set sh2 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" + +set sh to sh1 & sh2 + +do shell script sh with prompt "RustDesk 需要停止服务" with administrator privileges \ No newline at end of file diff --git a/src/platform/privileges_scripts/stop_service.scpt b/src/platform/privileges_scripts/stop_service.scpt new file mode 100644 index 000000000..58be8292f --- /dev/null +++ b/src/platform/privileges_scripts/stop_service.scpt @@ -0,0 +1,7 @@ +set sh1 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" + +set sh2 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" + +set sh to sh1 & sh2 + +do shell script sh with prompt "RustDesk 需要停止服务" with administrator privileges \ No newline at end of file diff --git a/src/ui.rs b/src/ui.rs index f12b6dcc5..db4e2ba16 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -360,22 +360,12 @@ impl UI { if value.is_empty() { options.remove(&key); } else { - options.insert(key, value); + options.insert(key.clone(), value.clone()); } ipc::set_options(options.clone()).ok(); - #[cfg(macos)] - if key == "stop-service" { - let mut service_script = "./privileges_scripts/stop_service.scpt"; - if value == "Y" { - command = "./privileges_scripts/launch_service.scpt"; - } - - std::process::Command::new("osascript") - .arg(service_script) - .status() - .unwrap() - .success(); + if cfg!(target_os = "macos") && &key == "stop-service" { + crate::platform::macos::launch_or_stop_daemon(value != "Y"); } } From 78450fda08f51d443eb83c377ef1df56baddea35 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Fri, 14 Jan 2022 03:38:22 +0800 Subject: [PATCH 10/13] fix CI failed build on linux --- src/server.rs | 1 + src/ui.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server.rs b/src/server.rs index 13e3a678d..713b97da6 100644 --- a/src/server.rs +++ b/src/server.rs @@ -13,6 +13,7 @@ use hbb_common::{ sodiumoxide::crypto::{box_, secretbox, sign}, timeout, tokio, ResultType, Stream, }; +#[cfg(target_os = "macos")] use notify::{watcher, RecursiveMode, Watcher}; use parity_tokio_ipc::ConnectionClient; use service::{GenericService, Service, ServiceTmpl, Subscriber}; diff --git a/src/ui.rs b/src/ui.rs index db4e2ba16..6502ec729 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -364,7 +364,8 @@ impl UI { } ipc::set_options(options.clone()).ok(); - if cfg!(target_os = "macos") && &key == "stop-service" { + #[cfg(target_os = "macos")] + if &key == "stop-service" { crate::platform::macos::launch_or_stop_daemon(value != "Y"); } } From fea4b068cd8c6666a33c578ac305f053a031f263 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Fri, 14 Jan 2022 03:43:01 +0800 Subject: [PATCH 11/13] fix CI failed build on linux --- src/server.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server.rs b/src/server.rs index 713b97da6..d0c28a9ff 100644 --- a/src/server.rs +++ b/src/server.rs @@ -273,6 +273,7 @@ pub async fn start_server(is_server: bool, _tray: bool) { log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); } + #[cfg(target_os = "macos")] sync_and_watch_config_dir().await; if is_server { From 1fda4c257dc2eeb3828294083a099534efedc3f2 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Fri, 14 Jan 2022 03:47:16 +0800 Subject: [PATCH 12/13] fix CI failed build on linux --- src/server.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server.rs b/src/server.rs index d0c28a9ff..70e254fb2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -326,6 +326,7 @@ pub async fn start_server(is_server: bool, _tray: bool) { } } +#[cfg(target_os = "macos")] async fn sync_and_watch_config_dir() { if crate::username() == "root" { return; @@ -381,6 +382,7 @@ async fn sync_and_watch_config_dir() { } } +#[cfg(target_os = "macos")] async fn sync_config_to_user(conn: &mut ConnectionTmpl) -> ResultType<()> { allow_err!( conn.send(&Data::SyncConfigToUserReq { @@ -402,6 +404,7 @@ async fn sync_config_to_user(conn: &mut ConnectionTmpl) -> Res Ok(()) } +#[cfg(target_os = "macos")] async fn sync_config_to_root( conn: &mut ConnectionTmpl, from: PathBuf, From 4d37a9ee2346562e60cbe18dc40116228ea0401d Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Fri, 14 Jan 2022 03:52:39 +0800 Subject: [PATCH 13/13] fix CI failed build on linux --- src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 39b52cb58..215aa67ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,10 @@ fn main() { ipc::set_password(args[1].to_owned()).unwrap(); } return; - } else if cfg!(target_os = "macos") && args[0] == "--daemon" { + } + + #[cfg(target_os = "macos")] + if args[0] == "--daemon" { log::info!("start --daemon"); crate::platform::start_daemon(); return;