privacy_mode.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. #[cfg(windows)]
  2. use crate::platform::is_installed;
  3. use crate::ui_interface::get_option;
  4. #[cfg(windows)]
  5. use crate::{
  6. display_service,
  7. ipc::{connect, Data},
  8. };
  9. use hbb_common::{
  10. anyhow::anyhow,
  11. bail, lazy_static,
  12. tokio::{self, sync::oneshot},
  13. ResultType,
  14. };
  15. use serde_derive::{Deserialize, Serialize};
  16. use std::{
  17. collections::HashMap,
  18. sync::{Arc, Mutex},
  19. };
  20. #[cfg(windows)]
  21. pub mod win_exclude_from_capture;
  22. #[cfg(windows)]
  23. mod win_input;
  24. #[cfg(windows)]
  25. pub mod win_mag;
  26. #[cfg(windows)]
  27. pub mod win_topmost_window;
  28. #[cfg(windows)]
  29. mod win_virtual_display;
  30. #[cfg(windows)]
  31. pub use win_virtual_display::restore_reg_connectivity;
  32. pub const INVALID_PRIVACY_MODE_CONN_ID: i32 = 0;
  33. pub const OCCUPIED: &'static str = "Privacy occupied by another one.";
  34. pub const TURN_OFF_OTHER_ID: &'static str =
  35. "Failed to turn off privacy mode that belongs to someone else.";
  36. pub const NO_PHYSICAL_DISPLAYS: &'static str = "no_need_privacy_mode_no_physical_displays_tip";
  37. pub const PRIVACY_MODE_IMPL_WIN_MAG: &str = "privacy_mode_impl_mag";
  38. pub const PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE: &str = "privacy_mode_impl_exclude_from_capture";
  39. pub const PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY: &str = "privacy_mode_impl_virtual_display";
  40. #[derive(Debug, Serialize, Deserialize, Clone)]
  41. #[serde(tag = "t", content = "c")]
  42. pub enum PrivacyModeState {
  43. OffSucceeded,
  44. OffByPeer,
  45. OffUnknown,
  46. }
  47. pub trait PrivacyMode: Sync + Send {
  48. fn is_async_privacy_mode(&self) -> bool;
  49. fn init(&self) -> ResultType<()>;
  50. fn clear(&mut self);
  51. fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType<bool>;
  52. fn turn_off_privacy(&mut self, conn_id: i32, state: Option<PrivacyModeState>)
  53. -> ResultType<()>;
  54. fn pre_conn_id(&self) -> i32;
  55. fn get_impl_key(&self) -> &str;
  56. #[inline]
  57. fn check_on_conn_id(&self, conn_id: i32) -> ResultType<bool> {
  58. let pre_conn_id = self.pre_conn_id();
  59. if pre_conn_id == conn_id {
  60. return Ok(true);
  61. }
  62. if pre_conn_id != INVALID_PRIVACY_MODE_CONN_ID {
  63. bail!(OCCUPIED);
  64. }
  65. Ok(false)
  66. }
  67. #[inline]
  68. fn check_off_conn_id(&self, conn_id: i32) -> ResultType<()> {
  69. let pre_conn_id = self.pre_conn_id();
  70. if pre_conn_id != INVALID_PRIVACY_MODE_CONN_ID
  71. && conn_id != INVALID_PRIVACY_MODE_CONN_ID
  72. && pre_conn_id != conn_id
  73. {
  74. bail!(TURN_OFF_OTHER_ID)
  75. }
  76. Ok(())
  77. }
  78. }
  79. lazy_static::lazy_static! {
  80. pub static ref DEFAULT_PRIVACY_MODE_IMPL: String = {
  81. #[cfg(windows)]
  82. {
  83. if win_exclude_from_capture::is_supported() {
  84. PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE
  85. } else {
  86. if display_service::is_privacy_mode_mag_supported() {
  87. PRIVACY_MODE_IMPL_WIN_MAG
  88. } else {
  89. if is_installed() {
  90. PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY
  91. } else {
  92. ""
  93. }
  94. }
  95. }.to_owned()
  96. }
  97. #[cfg(not(windows))]
  98. {
  99. "".to_owned()
  100. }
  101. };
  102. static ref PRIVACY_MODE: Arc<Mutex<Option<Box<dyn PrivacyMode>>>> = {
  103. let mut cur_impl = get_option("privacy-mode-impl-key".to_owned());
  104. if !get_supported_privacy_mode_impl().iter().any(|(k, _)| k == &cur_impl) {
  105. cur_impl = DEFAULT_PRIVACY_MODE_IMPL.to_owned();
  106. }
  107. let privacy_mode = match PRIVACY_MODE_CREATOR.lock().unwrap().get(&(&cur_impl as &str)) {
  108. Some(creator) => Some(creator(&cur_impl)),
  109. None => None,
  110. };
  111. Arc::new(Mutex::new(privacy_mode))
  112. };
  113. }
  114. pub type PrivacyModeCreator = fn(impl_key: &str) -> Box<dyn PrivacyMode>;
  115. lazy_static::lazy_static! {
  116. static ref PRIVACY_MODE_CREATOR: Arc<Mutex<HashMap<&'static str, PrivacyModeCreator>>> = {
  117. #[cfg(not(windows))]
  118. let map: HashMap<&'static str, PrivacyModeCreator> = HashMap::new();
  119. #[cfg(windows)]
  120. let mut map: HashMap<&'static str, PrivacyModeCreator> = HashMap::new();
  121. #[cfg(windows)]
  122. {
  123. if win_exclude_from_capture::is_supported() {
  124. map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, |impl_key: &str| {
  125. Box::new(win_exclude_from_capture::PrivacyModeImpl::new(impl_key))
  126. });
  127. } else {
  128. map.insert(win_mag::PRIVACY_MODE_IMPL, |impl_key: &str| {
  129. Box::new(win_mag::PrivacyModeImpl::new(impl_key))
  130. });
  131. }
  132. map.insert(win_virtual_display::PRIVACY_MODE_IMPL, |impl_key: &str| {
  133. Box::new(win_virtual_display::PrivacyModeImpl::new(impl_key))
  134. });
  135. }
  136. Arc::new(Mutex::new(map))
  137. };
  138. }
  139. #[inline]
  140. pub fn init() -> Option<ResultType<()>> {
  141. Some(PRIVACY_MODE.lock().unwrap().as_ref()?.init())
  142. }
  143. #[inline]
  144. pub fn clear() -> Option<()> {
  145. Some(PRIVACY_MODE.lock().unwrap().as_mut()?.clear())
  146. }
  147. #[inline]
  148. pub fn switch(impl_key: &str) {
  149. let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap();
  150. if let Some(privacy_mode) = privacy_mode_lock.as_ref() {
  151. if privacy_mode.get_impl_key() == impl_key {
  152. return;
  153. }
  154. }
  155. if let Some(creator) = PRIVACY_MODE_CREATOR.lock().unwrap().get(impl_key) {
  156. *privacy_mode_lock = Some(creator(impl_key));
  157. }
  158. }
  159. fn get_supported_impl(impl_key: &str) -> String {
  160. let supported_impls = get_supported_privacy_mode_impl();
  161. if supported_impls.iter().any(|(k, _)| k == &impl_key) {
  162. return impl_key.to_owned();
  163. };
  164. // TODO: Is it a good idea to use fallback here? Because user do not know the fallback.
  165. // fallback
  166. let mut cur_impl = get_option("privacy-mode-impl-key".to_owned());
  167. if !get_supported_privacy_mode_impl()
  168. .iter()
  169. .any(|(k, _)| k == &cur_impl)
  170. {
  171. // fallback
  172. cur_impl = DEFAULT_PRIVACY_MODE_IMPL.to_owned();
  173. }
  174. cur_impl
  175. }
  176. pub async fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>> {
  177. if is_async_privacy_mode() {
  178. turn_on_privacy_async(impl_key.to_string(), conn_id).await
  179. } else {
  180. turn_on_privacy_sync(impl_key, conn_id)
  181. }
  182. }
  183. #[inline]
  184. fn is_async_privacy_mode() -> bool {
  185. PRIVACY_MODE
  186. .lock()
  187. .unwrap()
  188. .as_ref()
  189. .map_or(false, |m| m.is_async_privacy_mode())
  190. }
  191. #[inline]
  192. async fn turn_on_privacy_async(impl_key: String, conn_id: i32) -> Option<ResultType<bool>> {
  193. let (tx, rx) = oneshot::channel();
  194. std::thread::spawn(move || {
  195. let res = turn_on_privacy_sync(&impl_key, conn_id);
  196. let _ = tx.send(res);
  197. });
  198. // Wait at most 5 seconds for the result.
  199. // Because it may take a long time to turn on the privacy mode with amyuni idd.
  200. match hbb_common::timeout(5000, rx).await {
  201. Ok(res) => match res {
  202. Ok(res) => res,
  203. Err(e) => Some(Err(anyhow!(e.to_string()))),
  204. },
  205. Err(e) => Some(Err(anyhow!(e.to_string()))),
  206. }
  207. }
  208. fn turn_on_privacy_sync(impl_key: &str, conn_id: i32) -> Option<ResultType<bool>> {
  209. // Check if privacy mode is already on or occupied by another one
  210. let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap();
  211. // Check or switch privacy mode implementation
  212. let impl_key = get_supported_impl(impl_key);
  213. let mut cur_impl_key = "".to_string();
  214. if let Some(privacy_mode) = privacy_mode_lock.as_ref() {
  215. cur_impl_key = privacy_mode.get_impl_key().to_string();
  216. let check_on_conn_id = privacy_mode.check_on_conn_id(conn_id);
  217. match check_on_conn_id.as_ref() {
  218. Ok(true) => {
  219. if cur_impl_key == impl_key {
  220. // Same peer, same implementation.
  221. return Some(Ok(true));
  222. } else {
  223. // Same peer, switch to new implementation.
  224. }
  225. }
  226. Err(_) => return Some(check_on_conn_id),
  227. _ => {}
  228. }
  229. }
  230. if cur_impl_key != impl_key {
  231. if let Some(creator) = PRIVACY_MODE_CREATOR
  232. .lock()
  233. .unwrap()
  234. .get(&(&impl_key as &str))
  235. {
  236. if let Some(privacy_mode) = privacy_mode_lock.as_mut() {
  237. privacy_mode.clear();
  238. }
  239. *privacy_mode_lock = Some(creator(&impl_key));
  240. } else {
  241. return Some(Err(anyhow!("Unsupported privacy mode: {}", impl_key)));
  242. }
  243. }
  244. // turn on privacy mode
  245. Some(privacy_mode_lock.as_mut()?.turn_on_privacy(conn_id))
  246. }
  247. #[inline]
  248. pub fn turn_off_privacy(conn_id: i32, state: Option<PrivacyModeState>) -> Option<ResultType<()>> {
  249. Some(
  250. PRIVACY_MODE
  251. .lock()
  252. .unwrap()
  253. .as_mut()?
  254. .turn_off_privacy(conn_id, state),
  255. )
  256. }
  257. #[inline]
  258. pub fn check_on_conn_id(conn_id: i32) -> Option<ResultType<bool>> {
  259. Some(
  260. PRIVACY_MODE
  261. .lock()
  262. .unwrap()
  263. .as_ref()?
  264. .check_on_conn_id(conn_id),
  265. )
  266. }
  267. #[cfg(windows)]
  268. #[tokio::main(flavor = "current_thread")]
  269. async fn set_privacy_mode_state(
  270. conn_id: i32,
  271. state: PrivacyModeState,
  272. impl_key: String,
  273. ms_timeout: u64,
  274. ) -> ResultType<()> {
  275. let mut c = connect(ms_timeout, "_cm").await?;
  276. c.send(&Data::PrivacyModeState((conn_id, state, impl_key)))
  277. .await
  278. }
  279. pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> {
  280. #[cfg(target_os = "windows")]
  281. {
  282. let mut vec_impls = Vec::new();
  283. if win_exclude_from_capture::is_supported() {
  284. vec_impls.push((
  285. PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE,
  286. "privacy_mode_impl_mag_tip",
  287. ));
  288. } else {
  289. if display_service::is_privacy_mode_mag_supported() {
  290. vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip"));
  291. }
  292. }
  293. if is_installed() && crate::platform::windows::is_self_service_running() {
  294. vec_impls.push((
  295. PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY,
  296. "privacy_mode_impl_virtual_display_tip",
  297. ));
  298. }
  299. vec_impls
  300. }
  301. #[cfg(not(target_os = "windows"))]
  302. {
  303. Vec::new()
  304. }
  305. }
  306. #[inline]
  307. pub fn get_cur_impl_key() -> Option<String> {
  308. PRIVACY_MODE
  309. .lock()
  310. .unwrap()
  311. .as_ref()
  312. .map(|pm| pm.get_impl_key().to_owned())
  313. }
  314. #[inline]
  315. pub fn is_current_privacy_mode_impl(impl_key: &str) -> bool {
  316. PRIVACY_MODE
  317. .lock()
  318. .unwrap()
  319. .as_ref()
  320. .map(|pm| pm.get_impl_key() == impl_key)
  321. .unwrap_or(false)
  322. }
  323. #[inline]
  324. #[cfg(not(windows))]
  325. pub fn check_privacy_mode_err(
  326. _privacy_mode_id: i32,
  327. _display_idx: usize,
  328. _timeout_millis: u64,
  329. ) -> String {
  330. "".to_owned()
  331. }
  332. #[inline]
  333. #[cfg(windows)]
  334. pub fn check_privacy_mode_err(
  335. privacy_mode_id: i32,
  336. display_idx: usize,
  337. timeout_millis: u64,
  338. ) -> String {
  339. // win magnifier implementation requires a test of creating a capturer.
  340. if is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) {
  341. crate::video_service::test_create_capturer(privacy_mode_id, display_idx, timeout_millis)
  342. } else {
  343. "".to_owned()
  344. }
  345. }
  346. #[inline]
  347. pub fn is_privacy_mode_supported() -> bool {
  348. !DEFAULT_PRIVACY_MODE_IMPL.is_empty()
  349. }
  350. #[inline]
  351. pub fn get_privacy_mode_conn_id() -> Option<i32> {
  352. PRIVACY_MODE
  353. .lock()
  354. .unwrap()
  355. .as_ref()
  356. .map(|pm| pm.pre_conn_id())
  357. }
  358. #[inline]
  359. pub fn is_in_privacy_mode() -> bool {
  360. PRIVACY_MODE
  361. .lock()
  362. .unwrap()
  363. .as_ref()
  364. .map(|pm| pm.pre_conn_id() != INVALID_PRIVACY_MODE_CONN_ID)
  365. .unwrap_or(false)
  366. }