approve mode, cm sync option

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2022-11-20 15:53:08 +08:00
parent 8b20237096
commit 05c549a5fe
39 changed files with 298 additions and 56 deletions

View File

@ -580,20 +580,21 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
return ChangeNotifierProvider.value( return ChangeNotifierProvider.value(
value: gFFI.serverModel, value: gFFI.serverModel,
child: Consumer<ServerModel>(builder: ((context, model, child) { child: Consumer<ServerModel>(builder: ((context, model, child) {
List<String> keys = [ List<String> passwordKeys = [
kUseTemporaryPassword, kUseTemporaryPassword,
kUsePermanentPassword, kUsePermanentPassword,
kUseBothPasswords, kUseBothPasswords,
]; ];
List<String> values = [ List<String> passwordValues = [
translate('Use temporary password'), translate('Use temporary password'),
translate('Use permanent password'), translate('Use permanent password'),
translate('Use both passwords'), translate('Use both passwords'),
]; ];
bool tmpEnabled = model.verificationMethod != kUsePermanentPassword; bool tmpEnabled = model.verificationMethod != kUsePermanentPassword;
bool permEnabled = model.verificationMethod != kUseTemporaryPassword; bool permEnabled = model.verificationMethod != kUseTemporaryPassword;
String currentValue = values[keys.indexOf(model.verificationMethod)]; String currentValue =
List<Widget> radios = values passwordValues[passwordKeys.indexOf(model.verificationMethod)];
List<Widget> radios = passwordValues
.map((value) => _Radio<String>( .map((value) => _Radio<String>(
context, context,
value: value, value: value,
@ -601,8 +602,8 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
label: value, label: value,
onChanged: ((value) { onChanged: ((value) {
() async { () async {
await model await model.setVerificationMethod(
.setVerificationMethod(keys[values.indexOf(value)]); passwordKeys[passwordValues.indexOf(value)]);
await model.updatePasswordModel(); await model.updatePasswordModel();
}(); }();
}), }),
@ -640,9 +641,30 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
)) ))
.toList(); .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: [ return _Card(title: 'Password', children: [
radios[0], _ComboBox(
_SubLabeledWidget( 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', 'Temporary Password Length',
Row( Row(
children: [ children: [
@ -650,10 +672,20 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
], ],
), ),
enabled: tmpEnabled && !locked), enabled: tmpEnabled && !locked),
radios[1], ),
_SubButton('Set permanent password', setPasswordDialog, Offstage(
offstage: !usePassword,
child: radios[1],
),
Offstage(
offstage: !usePassword,
child: _SubButton('Set permanent password', setPasswordDialog,
permEnabled && !locked), permEnabled && !locked),
radios[2], ),
Offstage(
offstage: !usePassword,
child: radios[2],
),
]); ]);
}))); })));
} }

View File

@ -84,7 +84,6 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (call.method == "new_remote_desktop") { if (call.method == "new_remote_desktop") {
final args = jsonDecode(call.arguments); final args = jsonDecode(call.arguments);
final id = args['id']; final id = args['id'];
ConnectionTypeState.init(id);
window_on_top(windowId()); window_on_top(windowId());
ConnectionTypeState.init(id); ConnectionTypeState.init(id);
tabController.add(TabInfo( tabController.add(TabInfo(

View File

@ -555,11 +555,12 @@ class _CmControlPanel extends StatelessWidget {
final bool canElevate = bind.cmCanElevate(); final bool canElevate = bind.cmCanElevate();
final model = Provider.of<ServerModel>(context); final model = Provider.of<ServerModel>(context);
final showElevation = canElevate && model.showElevation; final showElevation = canElevate && model.showElevation;
final showAccept = model.approveMode != 'password';
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Offstage( Offstage(
offstage: !showElevation, offstage: !showElevation || !showAccept,
child: buildButton(context, color: Colors.green[700], onClick: () { child: buildButton(context, color: Colors.green[700], onClick: () {
handleAccept(context); handleAccept(context);
handleElevate(context); handleElevate(context);
@ -575,11 +576,17 @@ class _CmControlPanel extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
if (showAccept)
Expanded( Expanded(
child: buildButton(context, color: MyTheme.accent, onClick: () { child: Column(
children: [
buildButton(context, color: MyTheme.accent, onClick: () {
handleAccept(context); handleAccept(context);
windowManager.minimize(); windowManager.minimize();
}, text: 'Accept', textColor: Colors.white)), }, text: 'Accept', textColor: Colors.white),
],
),
),
Expanded( Expanded(
child: buildButton(context, child: buildButton(context,
color: Colors.transparent, color: Colors.transparent,
@ -621,7 +628,7 @@ class _CmControlPanel extends StatelessWidget {
); );
} }
return Container( return Container(
height: 35, height: 30,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color, borderRadius: BorderRadius.circular(4), border: border), color: color, borderRadius: BorderRadius.circular(4), border: border),
child: InkWell( child: InkWell(

View File

@ -255,6 +255,9 @@ class FfiModel with ChangeNotifier {
} else if (type == 'restarting') { } else if (type == 'restarting') {
showMsgBox(id, type, title, text, link, false, dialogManager, showMsgBox(id, type, title, text, link, false, dialogManager,
hasCancel: false); hasCancel: false);
} else if (type == 'wait-remote-accept-nook') {
msgBoxCommon(dialogManager, title, Text(translate(text)),
[msgBoxButton("Cancel", closeConnection)]);
} else { } else {
var hasRetry = evt['hasRetry'] == 'true'; var hasRetry = evt['hasRetry'] == 'true';
showMsgBox(id, type, title, text, link, hasRetry, dialogManager); showMsgBox(id, type, title, text, link, hasRetry, dialogManager);

View File

@ -31,6 +31,7 @@ class ServerModel with ChangeNotifier {
int _connectStatus = 0; // Rendezvous Server status int _connectStatus = 0; // Rendezvous Server status
String _verificationMethod = ""; String _verificationMethod = "";
String _temporaryPasswordLength = ""; String _temporaryPasswordLength = "";
String _approveMode = "";
late String _emptyIdShow; late String _emptyIdShow;
late final IDTextEditingController _serverId; late final IDTextEditingController _serverId;
@ -68,6 +69,8 @@ class ServerModel with ChangeNotifier {
return _verificationMethod; return _verificationMethod;
} }
String get approveMode => _approveMode;
setVerificationMethod(String method) async { setVerificationMethod(String method) async {
await bind.mainSetOption(key: "verification-method", value: method); 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); 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 serverId => _serverId;
TextEditingController get serverPasswd => _serverPasswd; TextEditingController get serverPasswd => _serverPasswd;
@ -98,8 +105,7 @@ class ServerModel with ChangeNotifier {
_emptyIdShow = translate("Generating ..."); _emptyIdShow = translate("Generating ...");
_serverId = IDTextEditingController(text: _emptyIdShow); _serverId = IDTextEditingController(text: _emptyIdShow);
Timer.periodic(Duration(seconds: 1), (timer) async { timerCallback() async {
if (isTest) return timer.cancel();
var status = await bind.mainGetOnlineStatue(); var status = await bind.mainGetOnlineStatue();
if (status > 0) { if (status > 0) {
status = 1; status = 1;
@ -115,8 +121,15 @@ class ServerModel with ChangeNotifier {
} }
updatePasswordModel(); updatePasswordModel();
}
if (!isTest) {
Future.delayed(Duration.zero, timerCallback);
Timer.periodic(Duration(milliseconds: 500), (timer) async {
await timerCallback();
}); });
} }
}
/// 1. check android permission /// 1. check android permission
/// 2. check config /// 2. check config
@ -151,11 +164,17 @@ class ServerModel with ChangeNotifier {
await bind.mainGetOption(key: "verification-method"); await bind.mainGetOption(key: "verification-method");
final temporaryPasswordLength = final temporaryPasswordLength =
await bind.mainGetOption(key: "temporary-password-length"); 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; final oldPwdText = _serverPasswd.text;
if (_serverPasswd.text != temporaryPassword) { if (_serverPasswd.text != temporaryPassword) {
_serverPasswd.text = temporaryPassword; _serverPasswd.text = temporaryPassword;
} }
if (verificationMethod == kUsePermanentPassword) { if (verificationMethod == kUsePermanentPassword ||
_approveMode == 'click') {
_serverPasswd.text = '-'; _serverPasswd.text = '-';
} }
if (oldPwdText != _serverPasswd.text) { if (oldPwdText != _serverPasswd.text) {

View File

@ -1337,6 +1337,15 @@ impl LoginConfigHandler {
self.password = Default::default(); self.password = Default::default();
interface.msgbox("re-input-password", err, "Do you want to enter again?", ""); interface.msgbox("re-input-password", err, "Do you want to enter again?", "");
true 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 { } else {
if err.contains(SCRAP_X11_REQUIRED) { if err.contains(SCRAP_X11_REQUIRED) {
interface.msgbox("error", "Login Error", err, SCRAP_X11_REF_URL); interface.msgbox("error", "Login Error", err, SCRAP_X11_REF_URL);
@ -1434,11 +1443,7 @@ impl LoginConfigHandler {
username: self.id.clone(), username: self.id.clone(),
password: password.into(), password: password.into(),
my_id, my_id,
my_name: if cfg!(windows) { my_name: crate::username(),
crate::platform::get_active_username()
} else {
crate::username()
},
option: self.get_option_message(true).into(), option: self.get_option_message(true).into(),
session_id: self.session_id, session_id: self.session_id,
version: crate::VERSION.to_string(), version: crate::VERSION.to_string(),

View File

@ -226,6 +226,7 @@ pub fn core_main() -> Option<Vec<String>> {
// meanwhile, return true to call flutter window to show control panel // meanwhile, return true to call flutter window to show control panel
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
crate::flutter::connection_manager::start_listen_ipc_thread(); crate::flutter::connection_manager::start_listen_ipc_thread();
crate::ui_interface::start_option_status_sync();
} }
} }
//_async_logger_holder.map(|x| x.flush()); //_async_logger_holder.map(|x| x.flush());

View File

@ -562,7 +562,7 @@ pub fn main_get_connect_status() -> String {
pub fn main_check_connect_status() { pub fn main_check_connect_status() {
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[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 { pub fn main_is_using_public_server() -> bool {

View File

@ -389,5 +389,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("This PC", "Aquest PC"), ("This PC", "Aquest PC"),
("or", "o"), ("or", "o"),
("Continue with", "Continuar amb"), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "使用"), ("Continue with", "使用"),
("Elevate", "提权"), ("Elevate", "提权"),
("Zoom cursor", "缩放鼠标"), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Continuar con"), ("Continue with", "Continuar con"),
("Elevate", "Elevar"), ("Elevate", "Elevar"),
("Zoom cursor", "Ampliar cursor"), ("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(); ].iter().cloned().collect();
} }

View File

@ -389,5 +389,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("or", "یا"), ("or", "یا"),
("Continue with", "ادامه با"), ("Continue with", "ادامه با"),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Continuer avec"), ("Continue with", "Continuer avec"),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Folytatás a következővel"), ("Continue with", "Folytatás a következővel"),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Continua con"), ("Continue with", "Continua con"),
("Elevate", "Eleva"), ("Elevate", "Eleva"),
("Zoom cursor", "Cursore zoom"), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Kontynuuj z"), ("Continue with", "Kontynuuj z"),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Continuar com"), ("Continue with", "Continuar com"),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "Продолжить с"), ("Continue with", "Продолжить с"),
("Elevate", "Повысить"), ("Elevate", "Повысить"),
("Zoom cursor", "Масштабировать курсор"), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", "bununla devam et"), ("Continue with", "bununla devam et"),
("Elevate", "Yükseltme"), ("Elevate", "Yükseltme"),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", "提權"), ("Elevate", "提權"),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -390,5 +390,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Continue with", ""), ("Continue with", ""),
("Elevate", ""), ("Elevate", ""),
("Zoom cursor", ""), ("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(); ].iter().cloned().collect();
} }

View File

@ -1046,6 +1046,14 @@ impl Connection {
} }
if !crate::is_ip(&lr.username) && lr.username != Config::get_id() { if !crate::is_ip(&lr.username) && lr.username != Config::get_id() {
self.send_login_error("Offline").await; 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() { } else if self.is_of_recent_session() {
self.try_start_cm(lr.my_id, lr.my_name, true); self.try_start_cm(lr.my_id, lr.my_name, true);
self.send_logon_response().await; self.send_logon_response().await;

View File

@ -135,6 +135,10 @@ impl SciterConnectionManager {
fn elevate_portable(&self, id: i32) { fn elevate_portable(&self, id: i32) {
crate::ui_cm_interface::elevate_portable(id); 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 { impl sciter::EventHandler for SciterConnectionManager {
@ -155,5 +159,6 @@ impl sciter::EventHandler for SciterConnectionManager {
fn send_msg(i32, String); fn send_msg(i32, String);
fn can_elevate(); fn can_elevate();
fn elevate_portable(i32); fn elevate_portable(i32);
fn get_option(String);
} }
} }

View File

@ -30,6 +30,7 @@ class Body: Reactor.Component
var right_style = show_chat ? "" : "display: none"; var right_style = show_chat ? "" : "display: none";
var disconnected = c.disconnected; var disconnected = c.disconnected;
var show_elevation_btn = handler.can_elevate() && show_elevation; 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 // below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter
return <div .content style="size:*"> return <div .content style="size:*">
<div .left-panel> <div .left-panel>
@ -58,16 +59,15 @@ class Body: Reactor.Component
{c.port_forward ? <div>Port Forwarding: {c.port_forward}</div> : ""} {c.port_forward ? <div>Port Forwarding: {c.port_forward}</div> : ""}
<div style="size:*"/> <div style="size:*"/>
<div .outer_buttons> <div .outer_buttons>
{!auth && !disconnected && show_elevation_btn ? <button #elevate_accept .control .elevate .button><span><span><span>{svg_elevate}</span><span>{translate('Accept')}</span></span></span></button> : "" } {!auth && !disconnected && show_elevation_btn && show_accept_btn ? <button #elevate_accept .control .elevate .button><span><span><span>{svg_elevate}</span><span>{translate('Accept')}</span></span></span></button> : "" }
{auth && !disconnected && show_elevation_btn ? <button #elevate .control .elevate .button><span><span><span>{svg_elevate}</span><span>{translate('Elevate')}</span></span></span></button> : "" } {auth && !disconnected && show_elevation_btn ? <button #elevate .control .elevate .button><span><span><span>{svg_elevate}</span><span>{translate('Elevate')}</span></span></span></button> : "" }
<div .inner_buttons style={auth ? "display:none;":""}> <div .inner_buttons style={auth ? "display:none;":""}>
{!auth ? <button #accept .control .button>{translate('Accept')}</button> : "" } {!auth && show_accept_btn ? <button #accept .control .button>{translate('Accept')}</button> : "" }
{!auth ? <button #dismiss .control .outline>{translate('Dismiss')}</button> : "" } {!auth ? <button #dismiss .control .outline>{translate('Dismiss')}</button> : "" }
</div> </div>
{auth && !disconnected ? <button #disconnect .control .button>{translate('Disconnect')}</button> : "" } {auth && !disconnected ? <button #disconnect .control .button>{translate('Disconnect')}</button> : "" }
{auth && disconnected ? <button #close .control .button>{translate('Close')}</button> : "" } {auth && disconnected ? <button #close .control .button>{translate('Close')}</button> : "" }
</div> </div>
<div style={!show_elevation_btn ? "height:1 em;" : "display:none;"}></div>
{c.is_file_transfer || c.port_forward ? "" : <div .chaticon>{svg_chat}</div>} {c.is_file_transfer || c.port_forward ? "" : <div .chaticon>{svg_chat}</div>}
</div> </div>
<div .right-panel style={right_style}> <div .right-panel style={right_style}>
@ -453,6 +453,21 @@ function getElaspsed(time, now) {
return out; 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() { function updateTime() {
self.timer(1s, function() { self.timer(1s, function() {
var now = new Date(); var now = new Date();

View File

@ -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) { } else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) {
callback = function() { view.close(); } 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; last_msgbox_tag = type + "-" + title + "-" + content + "-" + link;
$(#msgbox).content(<MsgboxComponent width={width} height={height} auto_login={auto_login} type={type} title={title} content={content} link={link} remember={remember} callback={callback} contentStyle={contentStyle} hasRetry={hasRetry} />); $(#msgbox).content(<MsgboxComponent width={width} height={height} auto_login={auto_login} type={type} title={title} content={content} link={link} remember={remember} callback={callback} contentStyle={contentStyle} hasRetry={hasRetry} />);

View File

@ -824,7 +824,8 @@ function watch_screen_recording() {
class PasswordEyeArea : Reactor.Component { class PasswordEyeArea : Reactor.Component {
render() { render() {
var method = handler.get_option('verification-method'); 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 return
<div .eye-area style="width: *"> <div .eye-area style="width: *">
<input|text @{this.input} readonly value={value} /> <input|text @{this.input} readonly value={value} />
@ -901,27 +902,46 @@ class PasswordArea: Reactor.Component {
function renderPop() { function renderPop() {
var method = handler.get_option('verification-method'); var method = handler.get_option('verification-method');
var approve_mode= handler.get_option('approve-mode');
var show_password = approve_mode != 'click';
return <popup><menu.context #edit-password-context> return <popup><menu.context #edit-password-context>
<li #use-temporary-password><span>{svg_checkmark}</span>{translate('Use temporary password')}</li> <li #approve-mode-password><span>{svg_checkmark}</span>{translate('Accept sessions via password')}</li>
<li #use-permanent-password><span>{svg_checkmark}</span>{translate('Use permanent password')}</li> <li #approve-mode-click><span>{svg_checkmark}</span>{translate('Accept sessions via click')}</li>
<li #use-both-passwords><span>{svg_checkmark}</span>{translate('Use both passwords')}</li> <li #approve-mode-both><span>{svg_checkmark}</span>{translate('Accept sessions via both')}</li>
<div .separator /> { !show_password ? '' : <div .separator /> }
<li #set-password disabled={ method == 'use-temporary-password' ? "true" : "false" }>{translate('Set permanent password')}</li> { !show_password ? '' : <li #use-temporary-password><span>{svg_checkmark}</span>{translate('Use temporary password')}</li> }
<TemporaryPasswordLengthMenu /> { !show_password ? '' : <li #use-permanent-password><span>{svg_checkmark}</span>{translate('Use permanent password')}</li> }
{ !show_password ? '' : <li #use-both-passwords><span>{svg_checkmark}</span>{translate('Use both passwords')}</li> }
{ !show_password ? '' : <div .separator /> }
{ !show_password ? '' : <li #set-password disabled={ method == 'use-temporary-password' ? "true" : "false" }>{translate('Set permanent password')}</li> }
{ !show_password ? '' : <TemporaryPasswordLengthMenu /> }
</menu></popup>; </menu></popup>;
} }
function toggleMenuState() { function toggleMenuState() {
var id = handler.get_option('verification-method'); var mode= handler.get_option('approve-mode');
if (id != 'use-temporary-password' && id != 'use-permanent-password') var mode_id;
id = 'use-both-passwords'; if (mode == 'password')
for (var el in [this.$(li#use-temporary-password), this.$(li#use-permanent-password), this.$(li#use-both-passwords)]) { mode_id = 'approve-mode-password';
el.attributes.toggleClass("selected", el.id == id); 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) { 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); var menu = $(menu#edit-password-context);
me.popup(menu); me.popup(menu);
} }
@ -954,16 +974,28 @@ class PasswordArea: Reactor.Component {
handler.set_option('verification-method', me.id); handler.set_option('verification-method', me.id);
this.toggleMenuState(); this.toggleMenuState();
passwordArea.update(); 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() { function updatePasswordArea() {
self.timer(1s, function() { self.timer(1s, function() {
var temporary_password = handler.temporary_password(); var temporary_password = handler.temporary_password();
var verification_method = handler.get_option('verification-method'); var verification_method = handler.get_option('verification-method');
var temporary_password_length = handler.get_option('temporary-password-length'); var temporary_password_length = handler.get_option('temporary-password-length');
var approve_mode = handler.get_option('approve-mode');
var update = false; var update = false;
if (password_cache[0] != temporary_password) { if (password_cache[0] != temporary_password) {
password_cache[0] = temporary_password; password_cache[0] = temporary_password;
@ -977,6 +1009,10 @@ function updatePasswordArea() {
password_cache[2] = temporary_password_length; password_cache[2] = temporary_password_length;
update = true; update = true;
} }
if (password_cache[3] != approve_mode) {
password_cache[3] = approve_mode;
update = true;
}
if (update) passwordArea.update(); if (update) passwordArea.update();
updatePasswordArea(); updatePasswordArea();
}); });

View File

@ -874,7 +874,12 @@ pub fn check_zombie(children: Children) {
} }
} }
pub(crate) fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender<ipc::Data> { pub fn start_option_status_sync() {
let _sender = SENDER.lock().unwrap();
}
// not call directly
fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender<ipc::Data> {
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>(); let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
std::thread::spawn(move || check_connect_status_(reconnect, rx)); std::thread::spawn(move || check_connect_status_(reconnect, rx));
tx tx
@ -898,7 +903,7 @@ pub fn account_auth_result() -> String {
// notice: avoiding create ipc connecton repeatly, // notice: avoiding create ipc connecton repeatly,
// because windows named pipe has serious memory leak issue. // because windows named pipe has serious memory leak issue.
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
pub(crate) async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc::Data>) { async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc::Data>) {
let mut key_confirmed = false; let mut key_confirmed = false;
let mut rx = rx; let mut rx = rx;
let mut mouse_time = 0; let mut mouse_time = 0;