From 1100b2a465e7f092e14069ce85a583392abd8897 Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 19 Apr 2023 14:39:22 +0800 Subject: [PATCH] show fingerprint Signed-off-by: 21pages --- flutter/lib/common.dart | 13 +++++- flutter/lib/common/shared_state.dart | 25 ++++++++++ flutter/lib/common/widgets/toolbar.dart | 7 +++ .../desktop/pages/desktop_setting_page.dart | 12 ++++- .../lib/desktop/pages/remote_tab_page.dart | 46 +++++++++++++++---- flutter/lib/mobile/pages/settings_page.dart | 16 +++++++ flutter/lib/models/model.dart | 2 + src/client.rs | 25 ++++++---- src/client/io_loop.rs | 4 +- src/common.rs | 14 ++++++ src/flutter.rs | 4 ++ src/flutter_ffi.rs | 4 ++ src/ipc.rs | 12 +++++ src/lang/ca.rs | 5 ++ src/lang/cn.rs | 5 ++ src/lang/cs.rs | 5 ++ src/lang/da.rs | 5 ++ src/lang/de.rs | 6 ++- src/lang/el.rs | 5 ++ src/lang/eo.rs | 5 ++ src/lang/es.rs | 5 ++ src/lang/fa.rs | 5 ++ src/lang/fr.rs | 5 ++ src/lang/hu.rs | 5 ++ src/lang/id.rs | 5 ++ src/lang/it.rs | 3 ++ src/lang/ja.rs | 5 ++ src/lang/ko.rs | 5 ++ src/lang/kz.rs | 5 ++ src/lang/lt.rs | 5 ++ src/lang/nl.rs | 5 ++ src/lang/pl.rs | 3 ++ src/lang/pt_PT.rs | 5 ++ src/lang/ptbr.rs | 5 ++ src/lang/ro.rs | 5 ++ src/lang/ru.rs | 5 ++ src/lang/sk.rs | 5 ++ src/lang/sl.rs | 5 ++ src/lang/sq.rs | 5 ++ src/lang/sr.rs | 5 ++ src/lang/sv.rs | 5 ++ src/lang/template.rs | 3 ++ src/lang/th.rs | 5 ++ src/lang/tr.rs | 5 ++ src/lang/tw.rs | 5 ++ src/lang/ua.rs | 5 ++ src/lang/vn.rs | 5 ++ src/port_forward.rs | 3 +- src/ui.rs | 5 ++ src/ui/index.tis | 1 + src/ui/remote.rs | 2 + src/ui_interface.rs | 17 +++++-- src/ui_session_interface.rs | 1 + 53 files changed, 350 insertions(+), 28 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index e91b8fcd2..d64f2cde5 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -797,6 +797,7 @@ void showToast(String text, {Duration timeout = const Duration(seconds: 2)}) { padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), child: Text( text, + textAlign: TextAlign.center, style: const TextStyle( decoration: TextDecoration.none, fontWeight: FontWeight.w300, @@ -1601,7 +1602,8 @@ bool callUniLinksUriHandler(Uri uri) { String? switch_uuid = param["switch_uuid"]; String? password = param["password"]; Future.delayed(Duration.zero, () { - rustDeskWinManager.newRemoteDesktop(peerId, password: password, switch_uuid: switch_uuid); + rustDeskWinManager.newRemoteDesktop(peerId, + password: password, switch_uuid: switch_uuid); }); return true; } @@ -2033,3 +2035,12 @@ Widget futureBuilder( } }); } + +void onCopyFingerprint(String value) { + if (value.isNotEmpty) { + Clipboard.setData(ClipboardData(text: value)); + showToast('$value\n${translate("Copied")}'); + } else { + showToast(translate("no fingerprints")); + } +} diff --git a/flutter/lib/common/shared_state.dart b/flutter/lib/common/shared_state.dart index 4659a01ce..e4711ddf8 100644 --- a/flutter/lib/common/shared_state.dart +++ b/flutter/lib/common/shared_state.dart @@ -121,6 +121,29 @@ class ConnectionTypeState { Get.find(tag: tag(id)); } +class FingerprintState { + static String tag(String id) => 'fingerprint_$id'; + + static void init(String id) { + final key = tag(id); + if (!Get.isRegistered(tag: key)) { + final RxString state = ''.obs; + Get.put(state, tag: key); + } else { + Get.find(tag: key).value = ''; + } + } + + static void delete(String id) { + final key = tag(id); + if (Get.isRegistered(tag: key)) { + Get.delete(tag: key); + } + } + + static RxString find(String id) => Get.find(tag: tag(id)); +} + class ShowRemoteCursorState { static String tag(String id) => 'show_remote_cursor_$id'; @@ -269,6 +292,7 @@ initSharedStates(String id) { KeyboardEnabledState.init(id); ShowRemoteCursorState.init(id); RemoteCursorMovedState.init(id); + FingerprintState.init(id); PeerBoolOption.init(id, 'zoom-cursor', () => false); } @@ -279,5 +303,6 @@ removeSharedStates(String id) { ShowRemoteCursorState.delete(id); KeyboardEnabledState.delete(id); RemoteCursorMovedState.delete(id); + FingerprintState.delete(id); PeerBoolOption.delete(id, 'zoom-cursor'); } diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index abf12de30..451c7d1a5 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -201,6 +201,13 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { ), onPressed: () => ffi.recordingModel.toggle())); } + // fingerprint + if (!isDesktop) { + v.add(TTextMenu( + child: Text(translate('Copy Fingerprint')), + onPressed: () => onCopyFingerprint(FingerprintState.find(id).value), + )); + } return v; } diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 93fffe3da..c083421fd 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1390,11 +1390,18 @@ class _AboutState extends State<_About> { final license = await bind.mainGetLicense(); final version = await bind.mainGetVersion(); final buildDate = await bind.mainGetBuildDate(); - return {'license': license, 'version': version, 'buildDate': buildDate}; + final fingerprint = await bind.mainGetFingerprint(); + return { + 'license': license, + 'version': version, + 'buildDate': buildDate, + 'fingerprint': fingerprint + }; }(), hasData: (data) { final license = data['license'].toString(); final version = data['version'].toString(); final buildDate = data['buildDate'].toString(); + final fingerprint = data['fingerprint'].toString(); const linkStyle = TextStyle(decoration: TextDecoration.underline); final scrollController = ScrollController(); return DesktopScrollWrapper( @@ -1415,6 +1422,9 @@ class _AboutState extends State<_About> { SelectionArea( child: Text('${translate('Build Date')}: $buildDate') .marginSymmetric(vertical: 4.0)), + SelectionArea( + child: Text('${translate('Fingerprint')}: $fingerprint') + .marginSymmetric(vertical: 4.0)), InkWell( onTap: () { launchUrlString('https://rustdesk.com/privacy'); diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 53774e36d..005c74522 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/consts.dart'; @@ -158,20 +159,36 @@ class _ConnectionTabPageState extends State { ], ); } else { - final msgDirect = translate( - connectionType.direct.value == ConnectionType.strDirect - ? 'Direct Connection' - : 'Relay Connection'); - final msgSecure = translate( - connectionType.secure.value == ConnectionType.strSecure - ? 'Secure Connection' - : 'Insecure Connection'); + bool secure = + connectionType.secure.value == ConnectionType.strSecure; + bool direct = + connectionType.direct.value == ConnectionType.strDirect; + var msgConn; + if (secure && direct) { + msgConn = translate("Direct and encrypted connection"); + } else if (secure && !direct) { + msgConn = translate("Relayed and encrypted connection"); + } else if (!secure && direct) { + msgConn = translate("Direct and unencrypted connection"); + } else { + msgConn = translate("Relayed and unencrypted connection"); + } + var msgFingerprint = '${translate('Fingerprint')}:\n'; + var fingerprint = FingerprintState.find(key).value; + if (fingerprint.length > 5 * 8) { + var first = fingerprint.substring(0, 39); + var second = fingerprint.substring(40); + msgFingerprint += '$first\n$second'; + } else { + msgFingerprint += fingerprint; + } + final tab = Row( mainAxisAlignment: MainAxisAlignment.center, children: [ icon, Tooltip( - message: '$msgDirect\n$msgSecure', + message: '$msgConn\n$msgFingerprint', child: SvgPicture.asset( 'assets/${connectionType.secure.value}${connectionType.direct.value}.svg', width: themeConf.iconSize, @@ -285,6 +302,17 @@ class _ConnectionTabPageState extends State { } } + menu.add(MenuEntryButton( + childBuilder: (TextStyle? style) => Text( + translate('Copy Fingerprint'), + style: style, + ), + proc: () => onCopyFingerprint(FingerprintState.find(key).value), + padding: padding, + dismissOnClicked: true, + dismissCallback: cancelFunc, + )); + return mod_menu.PopupMenu( items: menu .map((entry) => entry.build( diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index ff7c9e240..103c3e9fd 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:settings_ui/settings_ui.dart'; @@ -45,6 +46,7 @@ class _SettingsState extends State with WidgetsBindingObserver { var _autoRecordIncomingSession = false; var _localIP = ""; var _directAccessPort = ""; + var _fingerprint = ""; @override void initState() { @@ -135,6 +137,12 @@ class _SettingsState extends State with WidgetsBindingObserver { _directAccessPort = directAccessPort; } + final fingerprint = await bind.mainGetFingerprint(); + if (_fingerprint != fingerprint) { + update = true; + _fingerprint = fingerprint; + } + if (update) { setState(() {}); } @@ -462,6 +470,14 @@ class _SettingsState extends State with WidgetsBindingObserver { )), ), leading: Icon(Icons.info)), + SettingsTile.navigation( + onPressed: (context) => onCopyFingerprint(_fingerprint), + title: Text(translate("Fingerprint")), + value: Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Text(_fingerprint), + ), + leading: Icon(Icons.fingerprint)), ], ), ], diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 77e1b8fbf..388f5bd59 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -224,6 +224,8 @@ class FfiModel with ChangeNotifier { parent.target?.chatModel.onVoiceCallIncoming(); } else if (name == "update_voice_call_state") { parent.target?.serverModel.updateVoiceCallState(evt); + } else if (name == "fingerprint") { + FingerprintState.find(peerId).value = evt['fingerprint'] ?? ''; } else { debugPrint("Unknown event name: $name"); } diff --git a/src/client.rs b/src/client.rs index 1c6f12108..d6d58136e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -200,7 +200,7 @@ impl Client { token: &str, conn_type: ConnType, interface: impl Interface, - ) -> ResultType<(Stream, bool)> { + ) -> ResultType<(Stream, bool, Option>)> { match Self::_start(peer, key, token, conn_type, interface).await { Err(err) => { let err_str = err.to_string(); @@ -221,7 +221,7 @@ impl Client { token: &str, conn_type: ConnType, interface: impl Interface, - ) -> ResultType<(Stream, bool)> { + ) -> ResultType<(Stream, bool, Option>)> { // to-do: remember the port for each peer, so that we can retry easier if hbb_common::is_ip_str(peer) { return Ok(( @@ -231,6 +231,7 @@ impl Client { ) .await?, true, + None, )); } // Allow connect to {domain}:{port} @@ -238,6 +239,7 @@ impl Client { return Ok(( socket_client::connect_tcp(peer, RENDEZVOUS_TIMEOUT).await?, true, + None, )); } let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await; @@ -333,7 +335,7 @@ impl Client { my_addr.is_ipv4(), ) .await?; - Self::secure_connection( + let pk = Self::secure_connection( peer, signed_id_pk, key, @@ -342,7 +344,7 @@ impl Client { interface, ) .await?; - return Ok((conn, false)); + return Ok((conn, false, pk)); } _ => { log::error!("Unexpected protobuf msg received: {:?}", msg_in); @@ -403,7 +405,7 @@ impl Client { token: &str, conn_type: ConnType, interface: impl Interface, - ) -> ResultType<(Stream, bool)> { + ) -> ResultType<(Stream, bool, Option>)> { let direct_failures = PeerConfig::load(peer_id).direct_failures; let mut connect_timeout = 0; const MIN: u64 = 1000; @@ -473,8 +475,9 @@ impl Client { } let mut conn = conn?; log::info!("{:?} used to establish connection", start.elapsed()); - Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface).await?; - Ok((conn, direct)) + let pk = Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface) + .await?; + Ok((conn, direct, pk)) } /// Establish secure connection with the server. @@ -485,17 +488,19 @@ impl Client { conn: &mut Stream, direct: bool, interface: impl Interface, - ) -> ResultType<()> { + ) -> ResultType>> { let rs_pk = get_rs_pk(if key.is_empty() { hbb_common::config::RS_PUB_KEY } else { key }); let mut sign_pk = None; + let mut option_pk = None; if !signed_id_pk.is_empty() && rs_pk.is_some() { if let Ok((id, pk)) = decode_id_pk(&signed_id_pk, &rs_pk.unwrap()) { if id == peer_id { sign_pk = Some(sign::PublicKey(pk)); + option_pk = Some(pk.to_vec()); } } if sign_pk.is_none() { @@ -507,7 +512,7 @@ impl Client { None => { // send an empty message out in case server is setting up secure and waiting for first message conn.send(&Message::new()).await?; - return Ok(()); + return Ok(option_pk); } }; match timeout(READ_TIMEOUT, conn.next()).await? { @@ -560,7 +565,7 @@ impl Client { bail!("Reset by the peer"); } } - Ok(()) + Ok(option_pk) } /// Request a relay connection to the server. diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index eccc837f0..59c35006c 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -121,9 +121,11 @@ impl Remote { ) .await { - Ok((mut peer, direct)) => { + Ok((mut peer, direct, pk)) => { self.handler.set_connection_type(peer.is_secured(), direct); // flutter -> connection_ready self.handler.set_connection_info(direct, false); + self.handler + .set_fingerprint(crate::common::pk_to_fingerprint(pk.unwrap_or_default())); // just build for now #[cfg(not(windows))] diff --git a/src/common.rs b/src/common.rs index c96e42b37..d66938cf7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -840,3 +840,17 @@ pub fn is_peer_version_ge(v: &str) -> bool { false } + +pub fn pk_to_fingerprint(pk: Vec) -> String { + let s: String = pk.iter().map(|u| format!("{:02x}", u)).collect(); + s.chars() + .enumerate() + .map(|(i, c)| { + if i > 0 && i % 4 == 0 { + format!(" {}", c) + } else { + format!("{}", c) + } + }) + .collect() +} diff --git a/src/flutter.rs b/src/flutter.rs index d2cba9dd7..6b8a9f128 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -395,6 +395,10 @@ impl InvokeUiSession for FlutterHandler { ); } + fn set_fingerprint(&self, fingerprint: String) { + self.push_event("fingerprint", vec![("fingerprint", &fingerprint)]); + } + fn job_error(&self, id: i32, err: String, file_num: i32) { self.push_event( "job_error", diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 0386c5ad3..29df39b8a 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -921,6 +921,10 @@ pub fn main_get_permanent_password() -> String { ui_interface::permanent_password() } +pub fn main_get_fingerprint() -> String { + get_fingerprint() +} + pub fn main_get_online_statue() -> i64 { ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone() } diff --git a/src/ipc.rs b/src/ipc.rs index 5f415c6e8..a3222dd02 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -383,6 +383,12 @@ async fn handle(data: Data, stream: &mut Connection) { )); } else if name == "rendezvous_servers" { value = Some(Config::get_rendezvous_servers().join(",")); + } else if name == "fingerprint" { + value = if Config::get_key_confirmed() { + Some(crate::common::pk_to_fingerprint(Config::get_key_pair().1)) + } else { + None + }; } else { value = None; } @@ -690,6 +696,12 @@ pub fn get_permanent_password() -> String { } } +pub fn get_fingerprint() -> String { + get_config("fingerprint") + .unwrap_or_default() + .unwrap_or_default() +} + pub fn set_permanent_password(v: String) -> ResultType<()> { Config::set_permanent_password(&v); set_config("permanent-password", v) diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 995b56f1b..49fd2fb89 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 7f94173f0..2daa44c64 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "desktop 未安装"), ("no_desktop_text_tip", "请安装 desktop"), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", "指纹"), + ("Copy Fingerprint", "复制指纹"), + ("no fingerprints", "没有指纹"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 94cbc0c24..3bbd3e9eb 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index d567799c7..d22cac717 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index b703880fd..11860601e 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -492,7 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "Es ist kein Desktop verfügbar."), ("no_desktop_text_tip", "Bitte installieren Sie den GNOME-Desktop."), ("No need to elevate", "Erhöhung der Rechte nicht erforderlich"), + ("System Sound", ""), + ("Default", ""), ("New RDP", "Neue RDP-Verbindung"), - ("Failed to listen on {}: {}", "Lauschen fehlgeschlagen auf Port {}: {}"), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 8929ca5e7..b071de54d 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 5762ca118..3916afc01 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 772ae03a4..4f6b6e6b1 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "No hay escritorio disponible"), ("no_desktop_text_tip", "Por favor, instala GNOME Desktop"), ("No need to elevate", "No es necesario elevar privilegios"), + ("System Sound", ""), + ("Default", ""), ("New RDP", "Nuevo RDP"), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 9daeec94b..b00046807 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "هیچ دسکتاپی در دسترس نیست"), ("no_desktop_text_tip", "لطفا دسکتاپ گنوم را نصب کنید"), ("No need to elevate", "نیازی به ارتقاء نیست"), + ("System Sound", ""), + ("Default", ""), ("New RDP", "ریموت جدید"), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index dcee91876..1850ff2f6 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index b82469c62..513c07e69 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 0316965af..76acc5a99 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index f18df3dec..2720934ed 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -495,5 +495,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("System Sound", "Dispositivo audio sistema"), ("Default", "Predefinita"), ("New RDP", "Nuovo RDP"), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index f980138b0..835a8e1ce 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index beded1c1e..1bd6bb4a4 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index ead19ea1f..3006abaa9 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 8bc81a01e..7e8ae803d 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "Nėra pasiekiamų nuotolinių darbalaukių"), ("no_desktop_text_tip", "Prašom įdiegti GNOME Desktop"), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index fc6ff1e45..7c62a4d28 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 9e7c7407e..b350f1f45 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -495,5 +495,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("System Sound", "Dźwięk Systemowy"), ("Default", "Domyślne"), ("New RDP", "Nowe RDP"), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 04e5c79bd..6814d8dcb 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 02c92875e..4a4a6401d 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 73e7161a3..d2a4cb265 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index a42ef5009..a08bb8113 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "Нет доступных рабочих столов"), ("no_desktop_text_tip", "Установите GNOME Desktop"), ("No need to elevate", "Повышение прав не требуется"), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 18a77b790..51f12c102 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index a6b3f76f6..52f1381c8 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 317b8c3be..86aae1150 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index adf5c539c..554bd7589 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 702cbab16..69fb3abb8 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index e7a85bd5b..9d567c9b4 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -495,5 +495,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("System Sound", ""), ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 1255c888b..172677cc3 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index d1389a9fa..9907141a3 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 7bb5d04e4..f9337827a 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", "沒有可用的桌面"), ("no_desktop_text_tip", "請安裝 GNOME 桌面"), ("No need to elevate", "不需要提升權限"), + ("System Sound", ""), + ("Default", ""), ("New RDP", "新的 RDP"), + ("Fingerprint", "指紋"), + ("Copy Fingerprint", "複製指紋"), + ("no fingerprints", "沒有指紋"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index bcda47591..6f460c1df 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 543155418..75d78fe72 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("no_desktop_title_tip", ""), ("no_desktop_text_tip", ""), ("No need to elevate", ""), + ("System Sound", ""), + ("Default", ""), ("New RDP", ""), + ("Fingerprint", ""), + ("Copy Fingerprint", ""), + ("no fingerprints", ""), ].iter().cloned().collect(); } diff --git a/src/port_forward.rs b/src/port_forward.rs index 4e05ad92f..028875fa3 100644 --- a/src/port_forward.rs +++ b/src/port_forward.rs @@ -154,7 +154,8 @@ async fn connect_and_login_2( } else { ConnType::PORT_FORWARD }; - let (mut stream, direct) = Client::start(id, key, token, conn_type, interface.clone()).await?; + let (mut stream, direct, _pk) = + Client::start(id, key, token, conn_type, interface.clone()).await?; let mut interface = interface; let mut buffer = Vec::new(); let mut received = false; diff --git a/src/ui.rs b/src/ui.rs index ca50fbf9d..d08e82a36 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -470,6 +470,10 @@ impl UI { get_version() } + fn get_fingerprint(&self) -> String { + get_fingerprint() + } + fn get_app_name(&self) -> String { get_app_name() } @@ -649,6 +653,7 @@ impl sciter::EventHandler for UI { fn get_software_update_url(); fn get_new_version(); fn get_version(); + fn get_fingerprint(); fn update_me(String); fn show_run_without_install(); fn run_without_install(); diff --git a/src/ui/index.tis b/src/ui/index.tis index b2f71dafb..011b895d2 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -364,6 +364,7 @@ class MyIdMenu: Reactor.Component { var name = handler.get_app_name(); msgbox("custom-nocancel-nook-hasclose", translate("About") + " " + name, "
\
Version: " + handler.get_version() + " \ +
Fingerprint: " + handler.get_fingerprint() + " \
Privacy Statement
\
Website
\
Copyright © 2022 Purslane Ltd.\ diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 6d7dc7b42..c161cddf3 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -144,6 +144,8 @@ impl InvokeUiSession for SciterHandler { self.call("setConnectionType", &make_args!(is_secured, direct)); } + fn set_fingerprint(&self, _fingerprint: String) {} + fn job_error(&self, id: i32, err: String, file_num: i32) { self.call("jobError", &make_args!(id, err, file_num)); } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 30c6b9ab4..10f2982f2 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -24,13 +24,12 @@ use hbb_common::{ rendezvous_proto::*, }; +use crate::common::SOFTWARE_UPDATE_URL; #[cfg(feature = "flutter")] use crate::hbbs_http::account; -use crate::{common::SOFTWARE_UPDATE_URL}; #[cfg(not(any(target_os = "ios")))] use crate::ipc; - type Message = RendezvousMessage; pub type Children = Arc)>>; @@ -515,8 +514,7 @@ pub fn get_error() -> String { #[cfg(target_os = "linux")] { let dtype = crate::platform::linux::get_display_server(); - if crate::platform::linux::DISPLAY_SERVER_WAYLAND == dtype - { + if crate::platform::linux::DISPLAY_SERVER_WAYLAND == dtype { return crate::server::wayland::common_get_error(); } if dtype != crate::platform::linux::DISPLAY_SERVER_X11 { @@ -852,6 +850,17 @@ pub fn get_user_default_option(key: String) -> String { UserDefaultConfig::load().get(&key) } +pub fn get_fingerprint() -> String { + #[cfg(any(target_os = "android", target_os = "ios"))] + if Config::get_key_confirmed() { + return crate::common::pk_to_fingerprint(Config::get_key_pair().1); + } else { + return "".to_owned(); + } + #[cfg(not(any(target_os = "android", target_os = "ios")))] + return ipc::get_fingerprint(); +} + // notice: avoiding create ipc connection repeatedly, // because windows named pipe has serious memory leak issue. #[cfg(not(any(target_os = "android", target_os = "ios")))] diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 779119221..191d71448 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -889,6 +889,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { fn close_success(&self); fn update_quality_status(&self, qs: QualityStatus); fn set_connection_type(&self, is_secured: bool, direct: bool); + fn set_fingerprint(&self, fingerprint: String); fn job_error(&self, id: i32, err: String, file_num: i32); fn job_done(&self, id: i32, file_num: i32); fn clear_all_jobs(&self);