Compare commits

...

3 Commits

Author SHA1 Message Date
rustdesk
f3bd9fa933 fixing https://github.com/rustdesk/rustdesk/issues/15261 2026-06-16 16:32:43 +08:00
rustdesk
bf206dc309 fixing https://github.com/rustdesk/rustdesk/issues/15293 2026-06-16 11:36:53 +08:00
fufesou
6d116cf1c9 fix(clipboard): Windows DIB images, fill missing alpha (#15296)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-16 11:29:53 +08:00
6 changed files with 109 additions and 15 deletions

2
Cargo.lock generated
View File

@@ -292,7 +292,7 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arboard"
version = "3.4.0"
source = "git+https://github.com/rustdesk-org/arboard#85be1218668ff218a7b170c9d424fde73e069914"
source = "git+https://github.com/rustdesk-org/arboard#c7d5781f563176df9efd8df6287e823fb1b9bed5"
dependencies = [
"clipboard-win",
"core-graphics 0.23.2",

View File

@@ -117,13 +117,13 @@ void showServerSettingsWithValue(
),
SizedBox(width: 8),
Expanded(
child: TextFormField(
child: serverSettingsTextFormField(
label: label,
controller: controller,
decoration: InputDecoration(
errorText: errorMsg.isEmpty ? null : errorMsg,
contentPadding:
EdgeInsets.symmetric(horizontal: 8, vertical: 12),
),
errorMsg: errorMsg,
contentPadding:
EdgeInsets.symmetric(horizontal: 8, vertical: 12),
showLabelText: false,
validator: validator,
autofocus: autofocus,
).workaroundFreezeLinuxMint(),
@@ -132,12 +132,10 @@ void showServerSettingsWithValue(
);
}
return TextFormField(
return serverSettingsTextFormField(
label: label,
controller: controller,
decoration: InputDecoration(
labelText: label,
errorText: errorMsg.isEmpty ? null : errorMsg,
),
errorMsg: errorMsg,
validator: validator,
).workaroundFreezeLinuxMint();
}
@@ -209,6 +207,35 @@ void showServerSettingsWithValue(
});
}
TextFormField serverSettingsTextFormField({
required String label,
required TextEditingController controller,
required String errorMsg,
String? Function(String?)? validator,
bool autofocus = false,
bool showLabelText = true,
EdgeInsetsGeometry? contentPadding,
}) {
return TextFormField(
controller: controller,
decoration: InputDecoration(
labelText: showLabelText ? label : null,
errorText: errorMsg.isEmpty ? null : errorMsg,
contentPadding: contentPadding,
),
validator: validator,
autofocus: autofocus,
keyboardType: TextInputType.visiblePassword,
textCapitalization: TextCapitalization.none,
autocorrect: false,
enableSuggestions: false,
smartDashesType: SmartDashesType.disabled,
smartQuotesType: SmartQuotesType.disabled,
enableIMEPersonalizedLearning: false,
spellCheckConfiguration: const SpellCheckConfiguration.disabled(),
);
}
void setPrivacyModeDialog(
OverlayDialogManager dialogManager,
List<TToggleMenu> privacyModeList,

View File

@@ -30,6 +30,7 @@ use uuid::Uuid;
use crate::{
check_port,
common::input::{MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP},
common::PLATFORM_ADDITION_IS_LOGIN_SCREEN,
create_symmetric_key_msg, decode_id_pk, get_rs_pk, is_keyboard_mode_supported,
kcp_stream::KcpStream,
secure_tcp,
@@ -1901,11 +1902,11 @@ impl LoginConfigHandler {
/// Check if the client should auto login.
/// Return password if the client should auto login, otherwise return empty string.
pub fn should_auto_login(&self) -> String {
pub fn should_auto_login(&self, pi: &PeerInfo) -> String {
let l = self.lock_after_session_end.v;
let a = !self.get_option("auto-login").is_empty();
let p = self.get_option("os-password");
if !p.is_empty() && l && a {
if !p.is_empty() && l && a && !peer_reports_unlocked_desktop(pi) {
p
} else {
"".to_owned()
@@ -2804,6 +2805,67 @@ impl LoginConfigHandler {
}
}
fn peer_reports_unlocked_desktop(pi: &PeerInfo) -> bool {
serde_json::from_str::<HashMap<String, serde_json::Value>>(&pi.platform_additions)
.ok()
.and_then(|platform_additions| {
platform_additions
.get(PLATFORM_ADDITION_IS_LOGIN_SCREEN)
.and_then(|value| value.as_bool())
})
== Some(false)
}
#[cfg(test)]
mod tests {
use hbb_common::message_proto::PeerInfo;
fn login_config_handler() -> super::LoginConfigHandler {
let mut handler = super::LoginConfigHandler::default();
handler.config.lock_after_session_end.v = true;
handler
.config
.options
.insert("auto-login".to_owned(), "Y".to_owned());
handler
.config
.options
.insert("os-password".to_owned(), "secret".to_owned());
handler
}
fn peer_info(platform_additions: &str) -> PeerInfo {
PeerInfo {
platform_additions: platform_additions.to_owned(),
..Default::default()
}
}
#[test]
fn should_auto_login_skips_unlocked_peer() {
let handler = login_config_handler();
let pi = peer_info(r#"{"is_login_screen":false}"#);
assert_eq!("", handler.should_auto_login(&pi));
}
#[test]
fn should_auto_login_keeps_peer_on_login_screen() {
let handler = login_config_handler();
let pi = peer_info(r#"{"is_login_screen":true}"#);
assert_eq!("secret", handler.should_auto_login(&pi));
}
#[test]
fn should_auto_login_keeps_legacy_peer_without_login_screen_state() {
let handler = login_config_handler();
let pi = peer_info("");
assert_eq!("secret", handler.should_auto_login(&pi));
}
}
/// Media data.
pub enum MediaData {
VideoQueue,

View File

@@ -59,6 +59,7 @@ pub const PLATFORM_WINDOWS: &str = "Windows";
pub const PLATFORM_LINUX: &str = "Linux";
pub const PLATFORM_MACOS: &str = "Mac OS";
pub const PLATFORM_ANDROID: &str = "Android";
pub const PLATFORM_ADDITION_IS_LOGIN_SCREEN: &str = "is_login_screen";
pub const TIMER_OUT: Duration = Duration::from_secs(1);
pub const DEFAULT_KEEP_ALIVE: i32 = 60_000;

View File

@@ -1623,6 +1623,10 @@ impl Connection {
}
#[cfg(target_os = "macos")]
{
platform_additions.insert(
crate::common::PLATFORM_ADDITION_IS_LOGIN_SCREEN.into(),
json!(crate::platform::is_prelogin() || crate::platform::is_locked()),
);
platform_additions.insert(
"supported_privacy_mode_impl".into(),
json!(privacy_mode::get_supported_privacy_mode_impl()),

View File

@@ -1806,7 +1806,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
return;
}
self.try_change_init_resolution(pi.current_display);
let p = self.lc.read().unwrap().should_auto_login();
let p = self.lc.read().unwrap().should_auto_login(&pi);
if !p.is_empty() {
input_os_password(p, true, self.clone());
}