feat: option, enable-privacy-mode & enable-perm-change-in-accept-window (#14875)

* feat: option, privacy mode

Signed-off-by: fufesou <linlong1266@gmail.com>

* feat(privacy mode): update libs/hbb_common

Signed-off-by: fufesou <linlong1266@gmail.com>

* feat(privacy mode): turn off on disable privacy mode

Signed-off-by: fufesou <linlong1266@gmail.com>

* feat(privacy mode): better check if supported

Signed-off-by: fufesou <linlong1266@gmail.com>

* feat(option): enable perm change in accept window

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2026-05-02 00:44:22 +08:00
committed by GitHub
parent d4a1430c27
commit 383a5c3478
70 changed files with 437 additions and 57 deletions

View File

@@ -241,6 +241,7 @@ pub struct Connection {
restart: bool,
recording: bool,
block_input: bool,
privacy_mode: bool,
control_permissions: Option<ControlPermissions>,
last_test_delay: Option<Instant>,
network_delay: u32,
@@ -431,6 +432,7 @@ impl Connection {
restart: Self::permission(keys::OPTION_ENABLE_REMOTE_RESTART, &control_permissions),
recording: Self::permission(keys::OPTION_ENABLE_RECORD_SESSION, &control_permissions),
block_input: Self::permission(keys::OPTION_ENABLE_BLOCK_INPUT, &control_permissions),
privacy_mode: Self::permission(keys::OPTION_ENABLE_PRIVACY_MODE, &control_permissions),
control_permissions,
last_test_delay: None,
network_delay: 0,
@@ -527,6 +529,9 @@ impl Connection {
if !conn.block_input {
conn.send_permission(Permission::BlockInput, false).await;
}
if !conn.privacy_mode {
conn.send_permission(Permission::PrivacyMode, false).await;
}
let mut test_delay_timer =
crate::rustdesk_interval(time::interval_at(Instant::now(), TEST_DELAY_TIMEOUT));
let mut last_recv_time = Instant::now();
@@ -674,6 +679,46 @@ impl Connection {
} else if &name == "block_input" {
conn.block_input = enabled;
conn.send_permission(Permission::BlockInput, enabled).await;
} else if &name == "privacy_mode" {
// Keep permission state and runtime state consistent:
// when revoking the permission, try to leave privacy mode first.
// Otherwise we could end up in an inconsistent state where
// permission looks disabled while privacy mode is still active.
if !enabled && privacy_mode::is_in_privacy_mode() {
if let Some(conn_id) = privacy_mode::get_privacy_mode_conn_id() {
if conn_id == conn.inner.id() {
let impl_key =
privacy_mode::get_cur_impl_key().unwrap_or_default();
let turn_off_res =
privacy_mode::turn_off_privacy(conn_id, None);
match turn_off_res {
Some(Ok(_)) => {
let msg_out = crate::common::make_privacy_mode_msg(
back_notification::PrivacyModeState::PrvOffByPeer,
impl_key.clone(),
);
conn.send(msg_out).await;
}
_ => {
let msg_out = Self::turn_off_privacy_result_to_msg(
turn_off_res,
impl_key,
);
conn.send(msg_out).await;
// Turn-off failed, so revert CM's optimistic toggle
// and keep the previous permission value.
conn.send_to_cm(ipc::Data::SwitchPermission {
name: "privacy_mode".to_owned(),
enabled: conn.privacy_mode,
});
continue;
}
}
}
}
}
conn.privacy_mode = enabled;
conn.send_permission(Permission::PrivacyMode, enabled).await;
}
}
ipc::Data::RawMessage(bytes) => {
@@ -978,7 +1023,7 @@ impl Connection {
if let Some(video_privacy_conn_id) = privacy_mode::get_privacy_mode_conn_id() {
if video_privacy_conn_id == id {
let _ = Self::turn_off_privacy_to_msg(id);
let _ = Self::turn_off_privacy_to_msg(id, String::new());
}
}
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
@@ -1900,6 +1945,7 @@ impl Connection {
restart: self.restart,
recording: self.recording,
block_input: self.block_input,
privacy_mode: self.privacy_mode,
from_switch: self.from_switch,
});
}
@@ -2175,6 +2221,7 @@ impl Connection {
keys::OPTION_ENABLE_REMOTE_RESTART => Some(Permission::restart),
keys::OPTION_ENABLE_RECORD_SESSION => Some(Permission::recording),
keys::OPTION_ENABLE_BLOCK_INPUT => Some(Permission::block_input),
keys::OPTION_ENABLE_PRIVACY_MODE => Some(Permission::privacy_mode),
_ => None,
};
if let Some(permission) = permission {
@@ -4145,6 +4192,15 @@ impl Connection {
}
async fn turn_on_privacy(&mut self, impl_key: String) {
if !self.is_authed_remote_conn() || !self.privacy_mode {
let msg_out = crate::common::make_privacy_mode_msg(
back_notification::PrivacyModeState::PrvOnFailedDenied,
impl_key,
);
self.send(msg_out).await;
return;
}
let msg_out = if !privacy_mode::is_privacy_mode_supported() {
crate::common::make_privacy_mode_msg_with_details(
back_notification::PrivacyModeState::PrvNotSupported,
@@ -4186,7 +4242,7 @@ impl Connection {
"Check privacy mode failed: {}, turn off privacy mode.",
&err_msg
);
let _ = Self::turn_off_privacy_to_msg(self.inner.id);
let _ = Self::turn_off_privacy_to_msg(self.inner.id, String::new());
crate::common::make_privacy_mode_msg_with_details(
back_notification::PrivacyModeState::PrvOnFailed,
err_msg,
@@ -4205,6 +4261,7 @@ impl Connection {
if privacy_mode::is_in_privacy_mode() {
let _ = Self::turn_off_privacy_to_msg(
privacy_mode::INVALID_PRIVACY_MODE_CONN_ID,
String::new(),
);
}
crate::common::make_privacy_mode_msg_with_details(
@@ -4232,14 +4289,23 @@ impl Connection {
impl_key,
)
} else {
Self::turn_off_privacy_to_msg(self.inner.id)
Self::turn_off_privacy_to_msg(self.inner.id, impl_key)
};
self.send(msg_out).await;
}
pub fn turn_off_privacy_to_msg(_conn_id: i32) -> Message {
let impl_key = "".to_owned();
match privacy_mode::turn_off_privacy(_conn_id, None) {
pub fn turn_off_privacy_to_msg(_conn_id: i32, impl_key: String) -> Message {
Self::turn_off_privacy_result_to_msg(
privacy_mode::turn_off_privacy(_conn_id, None),
impl_key,
)
}
fn turn_off_privacy_result_to_msg(
turn_off_res: Option<hbb_common::ResultType<()>>,
impl_key: String,
) -> Message {
match turn_off_res {
Some(Ok(_)) => crate::common::make_privacy_mode_msg(
back_notification::PrivacyModeState::PrvOffSucceeded,
impl_key,