From a1c4b08535f375f5b461b883568e9bcd5ae0c2b4 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 14 Jan 2022 00:32:09 +0800 Subject: [PATCH] simple privacy demo Signed-off-by: fufesou --- src/platform/windows.rs | 3 +- src/server/connection.rs | 117 ++++++++++++++++++++++++++++++++------- src/ui/header.tis | 5 +- 3 files changed, 102 insertions(+), 23 deletions(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 074b3ccd1..b0c556bb5 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1013,11 +1013,10 @@ fn run_cmds(cmds: String, show: bool) -> ResultType<()> { Ok(()) } -pub fn toggle_privacy_mode(v: bool) { +pub fn toggle_blank_screen(v: bool) { let v = if v { TRUE } else { FALSE }; unsafe { blank_screen(v); - BlockInput(v); } } diff --git a/src/server/connection.rs b/src/server/connection.rs index 75a9071f8..963c7e79b 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -15,6 +15,7 @@ use hbb_common::{ tokio_util::codec::{BytesCodec, Framed}, }; use sha2::{Digest, Sha256}; +use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; pub type Sender = mpsc::UnboundedSender<(Instant, Arc)>; @@ -84,6 +85,14 @@ const MILLI1: Duration = Duration::from_millis(1); const SEND_TIMEOUT_VIDEO: u64 = 12_000; const SEND_TIMEOUT_OTHER: u64 = SEND_TIMEOUT_VIDEO * 10; +type SyncFunc = Box; + +enum BlankChannelMsg { + On, + Off, + Exit, +} + impl Connection { pub async fn start( addr: SocketAddr, @@ -157,6 +166,12 @@ impl Connection { }, ); + let (input_sender, input_receiver) = sync_channel(1); + + let (blank_sender, blank_receiver) = sync_channel(1); + let _ = std::thread::spawn(move || Self::handle_input(input_receiver)); + let blank_handler = std::thread::spawn(move || Self::handle_blank(blank_receiver)); + loop { tokio::select! { biased; // video has higher priority @@ -232,7 +247,7 @@ impl Connection { Ok(bytes) => { last_recv_time = Instant::now(); if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { - if !conn.on_message(msg_in).await { + if !conn.on_message(msg_in, input_sender.clone(), blank_sender.clone()).await { break; } } @@ -297,6 +312,14 @@ impl Connection { } } + blank_sender.send(BlankChannelMsg::Exit).unwrap(); + if let Err(e) = blank_handler.join() { + log::error!("Failed to join blank thread, {:?}", e); + }; + + crate::platform::block_input(false); + crate::platform::toggle_blank_screen(false); + video_service::notify_video_frame_feched(id, None); super::video_service::update_test_latency(id, 0); super::video_service::update_image_quality(id, None); @@ -305,6 +328,44 @@ impl Connection { } } + // TODO: + // 1. Send "Block Input" and "Privacy Mode" when connection established. + // 2. Ctrl + Alt + Del will break "Block Input" + fn handle_input(receiver: Receiver) { + loop { + match receiver.recv() { + Ok(mut f) => { + f(); + } + _ => break, + } + } + } + + fn handle_blank(receiver: Receiver) { + let mut last_privacy = false; + loop { + match receiver.recv_timeout(std::time::Duration::from_millis(500)) { + Ok(v) => match v { + BlankChannelMsg::On => { + crate::platform::toggle_blank_screen(true); + last_privacy = true; + } + BlankChannelMsg::Off => { + crate::platform::toggle_blank_screen(false); + last_privacy = false; + } + _ => break, + }, + _ => { + if last_privacy { + crate::platform::toggle_blank_screen(true); + } + } + } + } + } + async fn try_port_forward_loop( &mut self, rx_from_cm: &mut mpsc::UnboundedReceiver, @@ -536,10 +597,15 @@ impl Connection { self.send(msg_out).await; } - async fn on_message(&mut self, msg: Message) -> bool { + async fn on_message( + &mut self, + msg: Message, + input_sender: SyncSender, + blank_sender: SyncSender, + ) -> bool { if let Some(message::Union::login_request(lr)) = msg.union { if let Some(o) = lr.option.as_ref() { - self.update_option(o); + self.update_option(o, input_sender, blank_sender); } if self.authorized { return true; @@ -654,7 +720,8 @@ impl Connection { match msg.union { Some(message::Union::mouse_event(me)) => { if self.keyboard { - handle_mouse(&me, self.inner.id()); + let conn_id = self.inner.id(); + input_sender.send(Box::new(move || handle_mouse(&me, conn_id))).unwrap(); } } Some(message::Union::key_event(mut me)) => { @@ -669,17 +736,19 @@ impl Connection { }; if is_press { if let Some(key_event::Union::unicode(_)) = me.union { - handle_key(&me); + input_sender.send(Box::new(move || handle_key(&me))).unwrap(); } else if let Some(key_event::Union::seq(_)) = me.union { - handle_key(&me); + input_sender.send(Box::new(move || handle_key(&me))).unwrap(); } else { - me.down = true; - handle_key(&me); - me.down = false; - handle_key(&me); + input_sender.send(Box::new(move || { + me.down = true; + handle_key(&me); + me.down = false; + handle_key(&me); + })).unwrap(); } } else { - handle_key(&me); + input_sender.send(Box::new(move || handle_key(&me))).unwrap(); } } } @@ -782,7 +851,7 @@ impl Connection { self.send_to_cm(ipc::Data::ChatMessage { text: c.text }); } Some(misc::Union::option(o)) => { - self.update_option(&o); + self.update_option(&o, input_sender, blank_sender); } Some(misc::Union::refresh_video(r)) => { if r { @@ -797,7 +866,12 @@ impl Connection { true } - fn update_option(&mut self, o: &OptionMessage) { + fn update_option( + &mut self, + o: &OptionMessage, + input_sender: SyncSender, + blank_sender: SyncSender, + ) { log::info!("Option update: {:?}", o); if let Ok(q) = o.image_quality.enum_value() { self.image_quality = q.value(); @@ -857,15 +931,23 @@ impl Connection { if let Ok(q) = o.privacy_mode.enum_value() { if q != BoolOption::NotSet { self.privacy_mode = q == BoolOption::Yes; - if self.privacy_mode && self.keyboard { - crate::platform::toggle_privacy_mode(true); + if self.keyboard { + if self.privacy_mode { + input_sender.send(Box::new(move||{crate::platform::block_input(true)})).unwrap(); + blank_sender.send(BlankChannelMsg::On).unwrap(); + } else { + input_sender.send(Box::new(move||{crate::platform::block_input(false)})).unwrap(); + blank_sender.send(BlankChannelMsg::Off).unwrap(); + } } } } if self.keyboard { if let Ok(q) = o.block_input.enum_value() { if q != BoolOption::NotSet { - crate::platform::block_input(q == BoolOption::Yes); + input_sender.send(Box::new(move || { + crate::platform::block_input(q == BoolOption::Yes) + })).unwrap(); } } } @@ -880,9 +962,6 @@ impl Connection { crate::platform::lock_screen(); super::video_service::switch_to_primary(); } - if self.privacy_mode { - crate::platform::toggle_privacy_mode(false); - } self.port_forward_socket.take(); } diff --git a/src/ui/header.tis b/src/ui/header.tis index 57ef01e78..f8d72a75b 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -130,7 +130,8 @@ class Header: Reactor.Component { {audio_enabled ?
  • {svg_checkmark}{translate('Mute')}
  • : ""} {keyboard_enabled && clipboard_enabled ?
  • {svg_checkmark}{translate('Disable clipboard')}
  • : ""} {keyboard_enabled ?
  • {svg_checkmark}{translate('Lock after session end')}
  • : ""} - {false && pi.platform == "Windows" ?
  • {svg_checkmark}{translate('Privacy mode')}
  • : ""} + {pi.platform == "Windows" ?
  • Block user input
  • : ""} + {pi.platform == "Windows" ?
  • {svg_checkmark}{translate('Privacy mode')}
  • : ""} ; } @@ -144,7 +145,7 @@ class Header: Reactor.Component { {keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ?
  • {translate('Insert')} Ctrl + Alt + Del
  • : ""}
    {keyboard_enabled ?
  • {translate('Insert Lock')}
  • : ""} - {false && pi.platform == "Windows" ?
  • Block user input
  • : ""} + {pi.platform == "Windows" ?
  • Block user input
  • : ""} {handler.support_refresh() ?
  • {translate('Refresh')}
  • : ""} ;