diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index c776f0e89..1a7e9aeb7 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -571,7 +571,8 @@ class _RemoteMenubarState extends State { ), ]); // {handler.get_audit_server() &&
  • {translate('Note')}
  • } - final auditServer = bind.sessionGetAuditServerSync(id: widget.id); + final auditServer = + bind.sessionGetAuditServerSync(id: widget.id, typ: "conn"); if (auditServer.isNotEmpty) { displayMenu.add( MenuEntryButton( diff --git a/src/common.rs b/src/common.rs index 9023780f4..fe76b3168 100644 --- a/src/common.rs +++ b/src/common.rs @@ -620,12 +620,12 @@ pub fn get_api_server(api: String, custom: String) -> String { "https://admin.rustdesk.com".to_owned() } -pub fn get_audit_server(api: String, custom: String) -> String { +pub fn get_audit_server(api: String, custom: String, typ: String) -> String { let url = get_api_server(api, custom); if url.is_empty() || url.contains("rustdesk.com") { return "".to_owned(); } - format!("{}/api/audit", url) + format!("{}/api/audit/{}", url, typ) } pub async fn post_request(url: String, body: String, header: &str) -> ResultType { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index ddfaad06d..dc9d7a04a 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -894,9 +894,9 @@ pub fn session_restart_remote_device(id: String) { } } -pub fn session_get_audit_server_sync(id: String) -> SyncReturn { +pub fn session_get_audit_server_sync(id: String, typ: String) -> SyncReturn { let res = if let Some(session) = SESSIONS.read().unwrap().get(&id) { - session.get_audit_server() + session.get_audit_server(typ) } else { "".to_owned() }; diff --git a/src/server/connection.rs b/src/server/connection.rs index fdd0ea77a..32ce97ea8 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -93,7 +93,8 @@ pub struct Connection { tx_input: std_mpsc::Sender, // handle input messages video_ack_required: bool, peer_info: (String, String), - api_server: String, + server_audit_conn: String, + server_audit_file: String, lr: LoginRequest, last_recv_time: Arc>, chat_unanswered: bool, @@ -184,7 +185,8 @@ impl Connection { tx_input, video_ack_required: false, peer_info: Default::default(), - api_server: "".to_owned(), + server_audit_conn: "".to_owned(), + server_audit_file: "".to_owned(), lr: Default::default(), last_recv_time: Arc::new(Mutex::new(Instant::now())), chat_unanswered: false, @@ -384,7 +386,7 @@ impl Connection { } else { conn.timer = time::interval_at(Instant::now() + SEC30, SEC30); } - conn.post_audit(json!({})); // heartbeat + conn.post_conn_audit(json!({})); // heartbeat }, Some((instant, value)) = rx_video.recv() => { if !conn.video_ack_required { @@ -497,7 +499,7 @@ impl Connection { conn.on_close(&err.to_string(), false).await; } - conn.post_audit(json!({ + conn.post_conn_audit(json!({ "action": "close", })); log::info!("#{} connection loop exited", id); @@ -601,7 +603,7 @@ impl Connection { if last_recv_time.elapsed() >= H1 { bail!("Timeout"); } - self.post_audit(json!({})); // heartbeat + self.post_conn_audit(json!({})); // heartbeat } } } @@ -650,7 +652,7 @@ impl Connection { msg_out.set_hash(self.hash.clone()); self.send(msg_out).await; self.get_api_server(); - self.post_audit(json!({ + self.post_conn_audit(json!({ "ip": addr.ip(), "action": "new", })); @@ -658,17 +660,23 @@ impl Connection { } fn get_api_server(&mut self) { - self.api_server = crate::get_audit_server( + self.server_audit_conn = crate::get_audit_server( Config::get_option("api-server"), Config::get_option("custom-rendezvous-server"), + "conn".to_owned(), + ); + self.server_audit_file = crate::get_audit_server( + Config::get_option("api-server"), + Config::get_option("custom-rendezvous-server"), + "file".to_owned(), ); } - fn post_audit(&self, v: Value) { - if self.api_server.is_empty() { + fn post_conn_audit(&self, v: Value) { + if self.server_audit_conn.is_empty() { return; } - let url = self.api_server.clone(); + let url = self.server_audit_conn.clone(); let mut v = v; v["id"] = json!(Config::get_id()); v["uuid"] = json!(base64::encode(hbb_common::get_uuid())); @@ -678,6 +686,41 @@ impl Connection { }); } + fn post_file_audit(&self, action: &str, path: &str, files: Vec<(String, i64)>, info: Value) { + if self.server_audit_file.is_empty() { + return; + } + let url = self.server_audit_file.clone(); + let file_num = files.len(); + let mut files = files; + files.sort_by(|a, b| b.1.cmp(&a.1)); + files.truncate(10); + let is_file = match action { + "send" | "receive" => files.len() == 1 && files[0].0.is_empty(), + "remove_dir" | "create_dir" => false, + "remove_file" => true, + _ => true, + }; + let mut info = info; + info["ip"] = json!(self.ip.clone()); + info["name"] = json!(self.lr.my_name.clone()); + info["num"] = json!(file_num); + info["files"] = json!(files); + let v = json!({ + "id":json!(Config::get_id()), + "uuid":json!(base64::encode(hbb_common::get_uuid())), + "Id":json!(self.inner.id), + "peer_id":json!(self.lr.my_id), + "action": action, + "path":path, + "is_file":is_file, + "info":json!(info).to_string(), + }); + tokio::spawn(async move { + allow_err!(Self::post_audit_async(url, v).await); + }); + } + #[inline] async fn post_audit_async(url: String, v: Value) -> ResultType<()> { crate::post_request(url, v.to_string(), "").await?; @@ -695,7 +738,7 @@ impl Connection { } else { 0 }; - self.post_audit(json!({"peer": self.peer_info, "Type": conn_type})); + self.post_conn_audit(json!({"peer": self.peer_info, "Type": conn_type})); #[allow(unused_mut)] let mut username = crate::platform::get_active_username(); let mut res = LoginResponse::new(); @@ -1225,8 +1268,18 @@ impl Connection { Ok(job) => { self.send(fs::new_dir(id, path, job.files().to_vec())) .await; + let mut files = job.files().to_owned(); self.read_jobs.push(job); self.timer = time::interval(MILLI1); + self.post_file_audit( + "send", + &s.path, + files + .drain(..) + .map(|f| (f.name, f.size as _)) + .collect(), + json!({}), + ); } } } @@ -1237,7 +1290,7 @@ impl Connection { &self.lr.version, )); self.send_fs(ipc::FS::NewWrite { - path: r.path, + path: r.path.clone(), id: r.id, file_num: r.file_num, files: r @@ -1248,6 +1301,16 @@ impl Connection { .collect(), overwrite_detection: od, }); + self.post_file_audit( + "receive", + &r.path, + r.files + .to_vec() + .drain(..) + .map(|f| (f.name, f.size as _)) + .collect(), + json!({}), + ); } Some(file_action::Union::RemoveDir(d)) => { self.send_fs(ipc::FS::RemoveDir { diff --git a/src/ui/header.tis b/src/ui/header.tis index 086696726..d1bb91cb9 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -208,7 +208,7 @@ class Header: Reactor.Component { {keyboard_enabled ?
  • {translate('OS Password')}
  • : ""}
  • {translate('Transfer File')}
  • {translate('TCP Tunneling')}
  • - {handler.get_audit_server() &&
  • {translate('Note')}
  • } + {handler.get_audit_server("conn") &&
  • {translate('Note')}
  • }
    {keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ?
  • {translate('Insert')} Ctrl + Alt + Del
  • : ""} {restart_enabled && (pi.platform == "Linux" || pi.platform == "Windows" || pi.platform == "Mac OS") ?
  • {translate('Restart Remote Device')}
  • : ""} diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 29b1a9eee..df5d98038 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -233,12 +233,12 @@ impl InvokeUiSession for SciterHandler { fn on_connected(&self, conn_type: ConnType) { match conn_type { - ConnType::RDP => {}, - ConnType::PORT_FORWARD => {}, - ConnType::FILE_TRANSFER => {}, + ConnType::RDP => {} + ConnType::PORT_FORWARD => {} + ConnType::FILE_TRANSFER => {} ConnType::DEFAULT_CONN => { crate::keyboard::client::start_grab_loop(); - }, + } } } @@ -348,7 +348,7 @@ impl sciter::EventHandler for SciterSession { } sciter::dispatch_script_call! { - fn get_audit_server(); + fn get_audit_server(String); fn send_note(String); fn is_xfce(); fn get_id(); diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 9868b5bb1..55984e343 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -173,7 +173,7 @@ impl Session { self.send(Data::Message(msg)); } - pub fn get_audit_server(&self) -> String { + pub fn get_audit_server(&self, typ: String) -> String { if self.lc.read().unwrap().conn_id <= 0 || LocalConfig::get_option("access_token").is_empty() { @@ -182,11 +182,12 @@ impl Session { crate::get_audit_server( Config::get_option("api-server"), Config::get_option("custom-rendezvous-server"), + typ, ) } pub fn send_note(&self, note: String) { - let url = self.get_audit_server(); + let url = self.get_audit_server("conn".to_string()); let id = self.id.clone(); let conn_id = self.lc.read().unwrap().conn_id; std::thread::spawn(move || {