diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index c03371a64..64ebc712e 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -580,20 +580,21 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { return ChangeNotifierProvider.value( value: gFFI.serverModel, child: Consumer(builder: ((context, model, child) { - List keys = [ + List passwordKeys = [ kUseTemporaryPassword, kUsePermanentPassword, kUseBothPasswords, ]; - List values = [ + List passwordValues = [ translate('Use temporary password'), translate('Use permanent password'), translate('Use both passwords'), ]; bool tmpEnabled = model.verificationMethod != kUsePermanentPassword; bool permEnabled = model.verificationMethod != kUseTemporaryPassword; - String currentValue = values[keys.indexOf(model.verificationMethod)]; - List radios = values + String currentValue = + passwordValues[passwordKeys.indexOf(model.verificationMethod)]; + List radios = passwordValues .map((value) => _Radio( context, value: value, @@ -601,8 +602,8 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { label: value, onChanged: ((value) { () async { - await model - .setVerificationMethod(keys[values.indexOf(value)]); + await model.setVerificationMethod( + passwordKeys[passwordValues.indexOf(value)]); await model.updatePasswordModel(); }(); }), @@ -640,20 +641,51 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { )) .toList(); + final modeKeys = ['password', 'click', '']; + final modeValues = [ + translate('Accept sessions via password'), + translate('Accept sessions via click'), + translate('Accept sessions via both'), + ]; + var modeInitialKey = model.approveMode; + if (!modeKeys.contains(modeInitialKey)) modeInitialKey = ''; + final usePassword = model.approveMode != 'click'; + return _Card(title: 'Password', children: [ - radios[0], - _SubLabeledWidget( - 'Temporary Password Length', - Row( - children: [ - ...lengthRadios, - ], - ), - enabled: tmpEnabled && !locked), - radios[1], - _SubButton('Set permanent password', setPasswordDialog, - permEnabled && !locked), - radios[2], + _ComboBox( + keys: modeKeys, + values: modeValues, + initialKey: modeInitialKey, + onChanged: (key) => model.setApproveMode(key), + ).marginOnly(left: _kContentHMargin), + Offstage( + offstage: !usePassword, + child: radios[0], + ), + Offstage( + offstage: !usePassword, + child: _SubLabeledWidget( + 'Temporary Password Length', + Row( + children: [ + ...lengthRadios, + ], + ), + enabled: tmpEnabled && !locked), + ), + Offstage( + offstage: !usePassword, + child: radios[1], + ), + Offstage( + offstage: !usePassword, + child: _SubButton('Set permanent password', setPasswordDialog, + permEnabled && !locked), + ), + Offstage( + offstage: !usePassword, + child: radios[2], + ), ]); }))); } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index df8256496..1e942272c 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -84,7 +84,6 @@ class _ConnectionTabPageState extends State { if (call.method == "new_remote_desktop") { final args = jsonDecode(call.arguments); final id = args['id']; - ConnectionTypeState.init(id); window_on_top(windowId()); ConnectionTypeState.init(id); tabController.add(TabInfo( diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 16abe0b64..ae69497bc 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -555,11 +555,12 @@ class _CmControlPanel extends StatelessWidget { final bool canElevate = bind.cmCanElevate(); final model = Provider.of(context); final showElevation = canElevate && model.showElevation; + final showAccept = model.approveMode != 'password'; return Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Offstage( - offstage: !showElevation, + offstage: !showElevation || !showAccept, child: buildButton(context, color: Colors.green[700], onClick: () { handleAccept(context); handleElevate(context); @@ -575,11 +576,17 @@ class _CmControlPanel extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Expanded( - child: buildButton(context, color: MyTheme.accent, onClick: () { - handleAccept(context); - windowManager.minimize(); - }, text: 'Accept', textColor: Colors.white)), + if (showAccept) + Expanded( + child: Column( + children: [ + buildButton(context, color: MyTheme.accent, onClick: () { + handleAccept(context); + windowManager.minimize(); + }, text: 'Accept', textColor: Colors.white), + ], + ), + ), Expanded( child: buildButton(context, color: Colors.transparent, @@ -621,7 +628,7 @@ class _CmControlPanel extends StatelessWidget { ); } return Container( - height: 35, + height: 30, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(4), border: border), child: InkWell( diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index cae4485cb..a7cd7a11c 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -255,6 +255,9 @@ class FfiModel with ChangeNotifier { } else if (type == 'restarting') { showMsgBox(id, type, title, text, link, false, dialogManager, hasCancel: false); + } else if (type == 'wait-remote-accept-nook') { + msgBoxCommon(dialogManager, title, Text(translate(text)), + [msgBoxButton("Cancel", closeConnection)]); } else { var hasRetry = evt['hasRetry'] == 'true'; showMsgBox(id, type, title, text, link, hasRetry, dialogManager); diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 1c0d1cbdd..a00630b22 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -31,6 +31,7 @@ class ServerModel with ChangeNotifier { int _connectStatus = 0; // Rendezvous Server status String _verificationMethod = ""; String _temporaryPasswordLength = ""; + String _approveMode = ""; late String _emptyIdShow; late final IDTextEditingController _serverId; @@ -68,6 +69,8 @@ class ServerModel with ChangeNotifier { return _verificationMethod; } + String get approveMode => _approveMode; + setVerificationMethod(String method) async { await bind.mainSetOption(key: "verification-method", value: method); } @@ -84,6 +87,10 @@ class ServerModel with ChangeNotifier { await bind.mainSetOption(key: "temporary-password-length", value: length); } + setApproveMode(String mode) async { + await bind.mainSetOption(key: 'approve-mode', value: mode); + } + TextEditingController get serverId => _serverId; TextEditingController get serverPasswd => _serverPasswd; @@ -98,8 +105,7 @@ class ServerModel with ChangeNotifier { _emptyIdShow = translate("Generating ..."); _serverId = IDTextEditingController(text: _emptyIdShow); - Timer.periodic(Duration(seconds: 1), (timer) async { - if (isTest) return timer.cancel(); + timerCallback() async { var status = await bind.mainGetOnlineStatue(); if (status > 0) { status = 1; @@ -115,7 +121,14 @@ class ServerModel with ChangeNotifier { } updatePasswordModel(); - }); + } + + if (!isTest) { + Future.delayed(Duration.zero, timerCallback); + Timer.periodic(Duration(milliseconds: 500), (timer) async { + await timerCallback(); + }); + } } /// 1. check android permission @@ -151,11 +164,17 @@ class ServerModel with ChangeNotifier { await bind.mainGetOption(key: "verification-method"); final temporaryPasswordLength = await bind.mainGetOption(key: "temporary-password-length"); + final approveMode = await bind.mainGetOption(key: 'approve-mode'); + if (_approveMode != approveMode) { + _approveMode = approveMode; + update = true; + } final oldPwdText = _serverPasswd.text; if (_serverPasswd.text != temporaryPassword) { _serverPasswd.text = temporaryPassword; } - if (verificationMethod == kUsePermanentPassword) { + if (verificationMethod == kUsePermanentPassword || + _approveMode == 'click') { _serverPasswd.text = '-'; } if (oldPwdText != _serverPasswd.text) { diff --git a/src/client.rs b/src/client.rs index c98561967..672a35693 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1337,6 +1337,15 @@ impl LoginConfigHandler { self.password = Default::default(); interface.msgbox("re-input-password", err, "Do you want to enter again?", ""); true + } else if err == "No Password Access" { + self.password = Default::default(); + interface.msgbox( + "wait-remote-accept-nook", + "Prompt", + "Please wait for the remote side to accept your session request...", + "", + ); + true } else { if err.contains(SCRAP_X11_REQUIRED) { interface.msgbox("error", "Login Error", err, SCRAP_X11_REF_URL); @@ -1434,11 +1443,7 @@ impl LoginConfigHandler { username: self.id.clone(), password: password.into(), my_id, - my_name: if cfg!(windows) { - crate::platform::get_active_username() - } else { - crate::username() - }, + my_name: crate::username(), option: self.get_option_message(true).into(), session_id: self.session_id, version: crate::VERSION.to_string(), diff --git a/src/core_main.rs b/src/core_main.rs index 13a2ef91c..f890a9525 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -226,6 +226,7 @@ pub fn core_main() -> Option> { // meanwhile, return true to call flutter window to show control panel #[cfg(feature = "flutter")] crate::flutter::connection_manager::start_listen_ipc_thread(); + crate::ui_interface::start_option_status_sync(); } } //_async_logger_holder.map(|x| x.flush()); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 36e38f86e..928bca26b 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -562,7 +562,7 @@ pub fn main_get_connect_status() -> String { pub fn main_check_connect_status() { #[cfg(not(any(target_os = "android", target_os = "ios")))] - check_mouse_time(); // avoid multi calls + start_option_status_sync(); // avoid multi calls } pub fn main_is_using_public_server() -> bool { diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 1958b5b94..a70fce1c9 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -389,5 +389,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("This PC", "Aquest PC"), ("or", "o"), ("Continue with", "Continuar amb"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 16bbdb590..4588a148f 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "使用"), ("Elevate", "提权"), ("Zoom cursor", "缩放鼠标"), + ("Accept sessions via password", "只允许密码访问"), + ("Accept sessions via click", "只允许点击访问"), + ("Accept sessions via both", "允许密码或点击访问"), + ("Please wait for the remote side to accept your session request...", "请等待对方接受你的连接..."), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 0f262cd25..46817bbc4 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index c7362e26f..6678e734a 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index acc22a461..28d220933 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 206229859..2fc63ecc2 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index ca866641a..4e04fa2a0 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuar con"), ("Elevate", "Elevar"), ("Zoom cursor", "Ampliar cursor"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index b602bd404..040dcf204 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -389,5 +389,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("or", "یا"), ("Continue with", "ادامه با"), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index f4ff46cdf..926ad26fc 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuer avec"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index aaad2e9f9..2cdb56b9b 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Folytatás a következővel"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 96e7d38f4..65d447021 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 61f289ad6..58d493785 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continua con"), ("Elevate", "Eleva"), ("Zoom cursor", "Cursore zoom"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 1ff301bba..c0e6b667d 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index aa6c01e3d..3f0e10645 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 05055d1a3..a2d6a6dce 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index c62007778..d440b06f1 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Kontynuuj z"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index ca0fcead9..71d3ffb53 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 41459404b..8a213d51c 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Continuar com"), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 4920c2826..db0209fa8 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "Продолжить с"), ("Elevate", "Повысить"), ("Zoom cursor", "Масштабировать курсор"), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 0844c8442..6d4a9d382 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 9f1779119..22bf2ac23 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 6f3c9ba92..bd439676e 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", "bununla devam et"), ("Elevate", "Yükseltme"), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 900f25ccd..ff544c1d8 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", "提權"), ("Zoom cursor", ""), + ("Accept sessions via password", "只允許密碼訪問"), + ("Accept sessions via click", "只允許點擊訪問"), + ("Accept sessions via both", "允許密碼或點擊訪問"), + ("Please wait for the remote side to accept your session request...", "請等待對方接受你的連接..."), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index b336b1e36..d7efe411b 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index c21fe8aa8..96ff195b9 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Continue with", ""), ("Elevate", ""), ("Zoom cursor", ""), + ("Accept sessions via password", ""), + ("Accept sessions via click", ""), + ("Accept sessions via both", ""), + ("Please wait for the remote side to accept your session request...", ""), ].iter().cloned().collect(); } diff --git a/src/server/connection.rs b/src/server/connection.rs index cb2ddc2c6..f49e293a2 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1046,6 +1046,14 @@ impl Connection { } if !crate::is_ip(&lr.username) && lr.username != Config::get_id() { self.send_login_error("Offline").await; + } else if Config::get_option("approve-mode") == "click" { + self.try_start_cm(lr.my_id, lr.my_name, false); + if hbb_common::get_version_number(&lr.version) + >= hbb_common::get_version_number("1.2.0") + { + self.send_login_error("No Password Access").await; + } + return true; } else if self.is_of_recent_session() { self.try_start_cm(lr.my_id, lr.my_name, true); self.send_logon_response().await; diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 7c0e3fe24..2bd8824db 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -135,6 +135,10 @@ impl SciterConnectionManager { fn elevate_portable(&self, id: i32) { crate::ui_cm_interface::elevate_portable(id); } + + fn get_option(&self, key: String) -> String { + crate::ui_interface::get_option(key) + } } impl sciter::EventHandler for SciterConnectionManager { @@ -155,5 +159,6 @@ impl sciter::EventHandler for SciterConnectionManager { fn send_msg(i32, String); fn can_elevate(); fn elevate_portable(i32); + fn get_option(String); } } diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 035b58650..4ecbe706c 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -30,6 +30,7 @@ class Body: Reactor.Component var right_style = show_chat ? "" : "display: none"; var disconnected = c.disconnected; var show_elevation_btn = handler.can_elevate() && show_elevation; + var show_accept_btn = handler.get_option('approve-mode') != 'password'; // below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter return
@@ -58,16 +59,15 @@ class Body: Reactor.Component {c.port_forward ?
Port Forwarding: {c.port_forward}
: ""}
- {!auth && !disconnected && show_elevation_btn ? : "" } + {!auth && !disconnected && show_elevation_btn && show_accept_btn ? : "" } {auth && !disconnected && show_elevation_btn ? : "" }
- {!auth ? : "" } + {!auth && show_accept_btn ? : "" } {!auth ? : "" }
{auth && !disconnected ? : "" } {auth && disconnected ? : "" }
-
{c.is_file_transfer || c.port_forward ? "" :
{svg_chat}
}
@@ -453,6 +453,21 @@ function getElaspsed(time, now) { return out; } +var ui_status_cache = [""]; +function check_update_ui() { + self.timer(1s, function() { + var approve_mode = handler.get_option('approve-mode'); + var changed = false; + if (ui_status_cache[0] != approve_mode) { + ui_status_cache[0] = approve_mode; + changed = true; + } + if (changed) update(); + check_update_ui(); + }); +} +check_update_ui(); + function updateTime() { self.timer(1s, function() { var now = new Date(); diff --git a/src/ui/common.tis b/src/ui/common.tis index 7507d4895..b6723b131 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -264,6 +264,13 @@ function msgbox(type, title, content, link="", callback=null, height=180, width= }; } else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) { callback = function() { view.close(); } + } else if (type == 'wait-remote-accept-nook') { + callback = function (res) { + if (!res) { + view.close(); + return; + } + }; } last_msgbox_tag = type + "-" + title + "-" + content + "-" + link; $(#msgbox).content(); diff --git a/src/ui/index.tis b/src/ui/index.tis index 31781c35e..840198896 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -824,7 +824,8 @@ function watch_screen_recording() { class PasswordEyeArea : Reactor.Component { render() { var method = handler.get_option('verification-method'); - var value = method != 'use-permanent-password' ? password_cache[0] : "-"; + var mode= handler.get_option('approve-mode'); + var value = mode == 'click' || method == 'use-permanent-password' ? "-" : password_cache[0]; return
@@ -901,27 +902,46 @@ class PasswordArea: Reactor.Component { function renderPop() { var method = handler.get_option('verification-method'); + var approve_mode= handler.get_option('approve-mode'); + var show_password = approve_mode != 'click'; return -
  • {svg_checkmark}{translate('Use temporary password')}
  • -
  • {svg_checkmark}{translate('Use permanent password')}
  • -
  • {svg_checkmark}{translate('Use both passwords')}
  • -
    -
  • {translate('Set permanent password')}
  • - +
  • {svg_checkmark}{translate('Accept sessions via password')}
  • +
  • {svg_checkmark}{translate('Accept sessions via click')}
  • +
  • {svg_checkmark}{translate('Accept sessions via both')}
  • + { !show_password ? '' :
    } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use temporary password')}
  • } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use permanent password')}
  • } + { !show_password ? '' :
  • {svg_checkmark}{translate('Use both passwords')}
  • } + { !show_password ? '' :
    } + { !show_password ? '' :
  • {translate('Set permanent password')}
  • } + { !show_password ? '' : } ; } function toggleMenuState() { - var id = handler.get_option('verification-method'); - if (id != 'use-temporary-password' && id != 'use-permanent-password') - id = 'use-both-passwords'; - for (var el in [this.$(li#use-temporary-password), this.$(li#use-permanent-password), this.$(li#use-both-passwords)]) { - el.attributes.toggleClass("selected", el.id == id); + var mode= handler.get_option('approve-mode'); + var mode_id; + if (mode == 'password') + mode_id = 'approve-mode-password'; + else if (mode == 'click') + mode_id = 'approve-mode-click'; + else + mode_id = 'approve-mode-both'; + var pwd_id = handler.get_option('verification-method'); + if (pwd_id != 'use-temporary-password' && pwd_id != 'use-permanent-password') + pwd_id = 'use-both-passwords'; + for (var el in this.$$(menu#edit-password-context>li)) { + if (el.id.indexOf("approve-mode-") == 0) + el.attributes.toggleClass("selected", el.id == mode_id); + if (el.id.indexOf("use-") == 0) + el.attributes.toggleClass("selected", el.id == pwd_id); } } event click $(svg#edit) (_, me) { - temporaryPasswordLengthMenu.update({show: true }); + var approve_mode= handler.get_option('approve-mode'); + var show_password = approve_mode != 'click'; + if(show_password && temporaryPasswordLengthMenu) temporaryPasswordLengthMenu.update({show: true }); var menu = $(menu#edit-password-context); me.popup(menu); } @@ -954,16 +974,28 @@ class PasswordArea: Reactor.Component { handler.set_option('verification-method', me.id); this.toggleMenuState(); passwordArea.update(); + } else if (me.id.indexOf('approve-mode') == 0) { + var approve_mode; + if (me.id == 'approve-mode-password') + approve_mode = 'password'; + else if (me.id == 'approve-mode-click') + approve_mode = 'click'; + else + approve_mode = ''; + handler.set_option('approve-mode', approve_mode); + this.toggleMenuState(); + passwordArea.update(); } } } -var password_cache = ["","",""]; +var password_cache = ["","","",""]; function updatePasswordArea() { self.timer(1s, function() { var temporary_password = handler.temporary_password(); var verification_method = handler.get_option('verification-method'); var temporary_password_length = handler.get_option('temporary-password-length'); + var approve_mode = handler.get_option('approve-mode'); var update = false; if (password_cache[0] != temporary_password) { password_cache[0] = temporary_password; @@ -977,6 +1009,10 @@ function updatePasswordArea() { password_cache[2] = temporary_password_length; update = true; } + if (password_cache[3] != approve_mode) { + password_cache[3] = approve_mode; + update = true; + } if (update) passwordArea.update(); updatePasswordArea(); }); diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 0e443ad61..e1dc3005e 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -874,7 +874,12 @@ pub fn check_zombie(children: Children) { } } -pub(crate) fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender { +pub fn start_option_status_sync() { + let _sender = SENDER.lock().unwrap(); +} + +// not call directly +fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender { let (tx, rx) = mpsc::unbounded_channel::(); std::thread::spawn(move || check_connect_status_(reconnect, rx)); tx @@ -898,7 +903,7 @@ pub fn account_auth_result() -> String { // notice: avoiding create ipc connecton repeatly, // because windows named pipe has serious memory leak issue. #[tokio::main(flavor = "current_thread")] -pub(crate) async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver) { +async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver) { let mut key_confirmed = false; let mut rx = rx; let mut mouse_time = 0;