show fingerprint

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-04-19 14:39:22 +08:00
parent 08c4d2a1cf
commit 1100b2a465
53 changed files with 350 additions and 28 deletions

View File

@ -797,6 +797,7 @@ void showToast(String text, {Duration timeout = const Duration(seconds: 2)}) {
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Text( child: Text(
text, text,
textAlign: TextAlign.center,
style: const TextStyle( style: const TextStyle(
decoration: TextDecoration.none, decoration: TextDecoration.none,
fontWeight: FontWeight.w300, fontWeight: FontWeight.w300,
@ -1601,7 +1602,8 @@ bool callUniLinksUriHandler(Uri uri) {
String? switch_uuid = param["switch_uuid"]; String? switch_uuid = param["switch_uuid"];
String? password = param["password"]; String? password = param["password"];
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
rustDeskWinManager.newRemoteDesktop(peerId, password: password, switch_uuid: switch_uuid); rustDeskWinManager.newRemoteDesktop(peerId,
password: password, switch_uuid: switch_uuid);
}); });
return true; 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"));
}
}

View File

@ -121,6 +121,29 @@ class ConnectionTypeState {
Get.find<ConnectionType>(tag: tag(id)); Get.find<ConnectionType>(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<RxString>(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<RxString>(tag: tag(id));
}
class ShowRemoteCursorState { class ShowRemoteCursorState {
static String tag(String id) => 'show_remote_cursor_$id'; static String tag(String id) => 'show_remote_cursor_$id';
@ -269,6 +292,7 @@ initSharedStates(String id) {
KeyboardEnabledState.init(id); KeyboardEnabledState.init(id);
ShowRemoteCursorState.init(id); ShowRemoteCursorState.init(id);
RemoteCursorMovedState.init(id); RemoteCursorMovedState.init(id);
FingerprintState.init(id);
PeerBoolOption.init(id, 'zoom-cursor', () => false); PeerBoolOption.init(id, 'zoom-cursor', () => false);
} }
@ -279,5 +303,6 @@ removeSharedStates(String id) {
ShowRemoteCursorState.delete(id); ShowRemoteCursorState.delete(id);
KeyboardEnabledState.delete(id); KeyboardEnabledState.delete(id);
RemoteCursorMovedState.delete(id); RemoteCursorMovedState.delete(id);
FingerprintState.delete(id);
PeerBoolOption.delete(id, 'zoom-cursor'); PeerBoolOption.delete(id, 'zoom-cursor');
} }

View File

@ -201,6 +201,13 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
), ),
onPressed: () => ffi.recordingModel.toggle())); onPressed: () => ffi.recordingModel.toggle()));
} }
// fingerprint
if (!isDesktop) {
v.add(TTextMenu(
child: Text(translate('Copy Fingerprint')),
onPressed: () => onCopyFingerprint(FingerprintState.find(id).value),
));
}
return v; return v;
} }

View File

@ -1390,11 +1390,18 @@ class _AboutState extends State<_About> {
final license = await bind.mainGetLicense(); final license = await bind.mainGetLicense();
final version = await bind.mainGetVersion(); final version = await bind.mainGetVersion();
final buildDate = await bind.mainGetBuildDate(); 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) { }(), hasData: (data) {
final license = data['license'].toString(); final license = data['license'].toString();
final version = data['version'].toString(); final version = data['version'].toString();
final buildDate = data['buildDate'].toString(); final buildDate = data['buildDate'].toString();
final fingerprint = data['fingerprint'].toString();
const linkStyle = TextStyle(decoration: TextDecoration.underline); const linkStyle = TextStyle(decoration: TextDecoration.underline);
final scrollController = ScrollController(); final scrollController = ScrollController();
return DesktopScrollWrapper( return DesktopScrollWrapper(
@ -1415,6 +1422,9 @@ class _AboutState extends State<_About> {
SelectionArea( SelectionArea(
child: Text('${translate('Build Date')}: $buildDate') child: Text('${translate('Build Date')}: $buildDate')
.marginSymmetric(vertical: 4.0)), .marginSymmetric(vertical: 4.0)),
SelectionArea(
child: Text('${translate('Fingerprint')}: $fingerprint')
.marginSymmetric(vertical: 4.0)),
InkWell( InkWell(
onTap: () { onTap: () {
launchUrlString('https://rustdesk.com/privacy'); launchUrlString('https://rustdesk.com/privacy');

View File

@ -4,6 +4,7 @@ import 'dart:ui' as ui;
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/common/shared_state.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
@ -158,20 +159,36 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
], ],
); );
} else { } else {
final msgDirect = translate( bool secure =
connectionType.direct.value == ConnectionType.strDirect connectionType.secure.value == ConnectionType.strSecure;
? 'Direct Connection' bool direct =
: 'Relay Connection'); connectionType.direct.value == ConnectionType.strDirect;
final msgSecure = translate( var msgConn;
connectionType.secure.value == ConnectionType.strSecure if (secure && direct) {
? 'Secure Connection' msgConn = translate("Direct and encrypted connection");
: 'Insecure 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( final tab = Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
icon, icon,
Tooltip( Tooltip(
message: '$msgDirect\n$msgSecure', message: '$msgConn\n$msgFingerprint',
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/${connectionType.secure.value}${connectionType.direct.value}.svg', 'assets/${connectionType.secure.value}${connectionType.direct.value}.svg',
width: themeConf.iconSize, width: themeConf.iconSize,
@ -285,6 +302,17 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
} }
} }
menu.add(MenuEntryButton<String>(
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<String>( return mod_menu.PopupMenu<String>(
items: menu items: menu
.map((entry) => entry.build( .map((entry) => entry.build(

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:settings_ui/settings_ui.dart'; import 'package:settings_ui/settings_ui.dart';
@ -45,6 +46,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
var _autoRecordIncomingSession = false; var _autoRecordIncomingSession = false;
var _localIP = ""; var _localIP = "";
var _directAccessPort = ""; var _directAccessPort = "";
var _fingerprint = "";
@override @override
void initState() { void initState() {
@ -135,6 +137,12 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
_directAccessPort = directAccessPort; _directAccessPort = directAccessPort;
} }
final fingerprint = await bind.mainGetFingerprint();
if (_fingerprint != fingerprint) {
update = true;
_fingerprint = fingerprint;
}
if (update) { if (update) {
setState(() {}); setState(() {});
} }
@ -462,6 +470,14 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
)), )),
), ),
leading: Icon(Icons.info)), 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)),
], ],
), ),
], ],

View File

@ -224,6 +224,8 @@ class FfiModel with ChangeNotifier {
parent.target?.chatModel.onVoiceCallIncoming(); parent.target?.chatModel.onVoiceCallIncoming();
} else if (name == "update_voice_call_state") { } else if (name == "update_voice_call_state") {
parent.target?.serverModel.updateVoiceCallState(evt); parent.target?.serverModel.updateVoiceCallState(evt);
} else if (name == "fingerprint") {
FingerprintState.find(peerId).value = evt['fingerprint'] ?? '';
} else { } else {
debugPrint("Unknown event name: $name"); debugPrint("Unknown event name: $name");
} }

View File

@ -200,7 +200,7 @@ impl Client {
token: &str, token: &str,
conn_type: ConnType, conn_type: ConnType,
interface: impl Interface, interface: impl Interface,
) -> ResultType<(Stream, bool)> { ) -> ResultType<(Stream, bool, Option<Vec<u8>>)> {
match Self::_start(peer, key, token, conn_type, interface).await { match Self::_start(peer, key, token, conn_type, interface).await {
Err(err) => { Err(err) => {
let err_str = err.to_string(); let err_str = err.to_string();
@ -221,7 +221,7 @@ impl Client {
token: &str, token: &str,
conn_type: ConnType, conn_type: ConnType,
interface: impl Interface, interface: impl Interface,
) -> ResultType<(Stream, bool)> { ) -> ResultType<(Stream, bool, Option<Vec<u8>>)> {
// to-do: remember the port for each peer, so that we can retry easier // to-do: remember the port for each peer, so that we can retry easier
if hbb_common::is_ip_str(peer) { if hbb_common::is_ip_str(peer) {
return Ok(( return Ok((
@ -231,6 +231,7 @@ impl Client {
) )
.await?, .await?,
true, true,
None,
)); ));
} }
// Allow connect to {domain}:{port} // Allow connect to {domain}:{port}
@ -238,6 +239,7 @@ impl Client {
return Ok(( return Ok((
socket_client::connect_tcp(peer, RENDEZVOUS_TIMEOUT).await?, socket_client::connect_tcp(peer, RENDEZVOUS_TIMEOUT).await?,
true, true,
None,
)); ));
} }
let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await; let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await;
@ -333,7 +335,7 @@ impl Client {
my_addr.is_ipv4(), my_addr.is_ipv4(),
) )
.await?; .await?;
Self::secure_connection( let pk = Self::secure_connection(
peer, peer,
signed_id_pk, signed_id_pk,
key, key,
@ -342,7 +344,7 @@ impl Client {
interface, interface,
) )
.await?; .await?;
return Ok((conn, false)); return Ok((conn, false, pk));
} }
_ => { _ => {
log::error!("Unexpected protobuf msg received: {:?}", msg_in); log::error!("Unexpected protobuf msg received: {:?}", msg_in);
@ -403,7 +405,7 @@ impl Client {
token: &str, token: &str,
conn_type: ConnType, conn_type: ConnType,
interface: impl Interface, interface: impl Interface,
) -> ResultType<(Stream, bool)> { ) -> ResultType<(Stream, bool, Option<Vec<u8>>)> {
let direct_failures = PeerConfig::load(peer_id).direct_failures; let direct_failures = PeerConfig::load(peer_id).direct_failures;
let mut connect_timeout = 0; let mut connect_timeout = 0;
const MIN: u64 = 1000; const MIN: u64 = 1000;
@ -473,8 +475,9 @@ impl Client {
} }
let mut conn = conn?; let mut conn = conn?;
log::info!("{:?} used to establish connection", start.elapsed()); log::info!("{:?} used to establish connection", start.elapsed());
Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface).await?; let pk = Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface)
Ok((conn, direct)) .await?;
Ok((conn, direct, pk))
} }
/// Establish secure connection with the server. /// Establish secure connection with the server.
@ -485,17 +488,19 @@ impl Client {
conn: &mut Stream, conn: &mut Stream,
direct: bool, direct: bool,
interface: impl Interface, interface: impl Interface,
) -> ResultType<()> { ) -> ResultType<Option<Vec<u8>>> {
let rs_pk = get_rs_pk(if key.is_empty() { let rs_pk = get_rs_pk(if key.is_empty() {
hbb_common::config::RS_PUB_KEY hbb_common::config::RS_PUB_KEY
} else { } else {
key key
}); });
let mut sign_pk = None; let mut sign_pk = None;
let mut option_pk = None;
if !signed_id_pk.is_empty() && rs_pk.is_some() { 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 let Ok((id, pk)) = decode_id_pk(&signed_id_pk, &rs_pk.unwrap()) {
if id == peer_id { if id == peer_id {
sign_pk = Some(sign::PublicKey(pk)); sign_pk = Some(sign::PublicKey(pk));
option_pk = Some(pk.to_vec());
} }
} }
if sign_pk.is_none() { if sign_pk.is_none() {
@ -507,7 +512,7 @@ impl Client {
None => { None => {
// send an empty message out in case server is setting up secure and waiting for first message // send an empty message out in case server is setting up secure and waiting for first message
conn.send(&Message::new()).await?; conn.send(&Message::new()).await?;
return Ok(()); return Ok(option_pk);
} }
}; };
match timeout(READ_TIMEOUT, conn.next()).await? { match timeout(READ_TIMEOUT, conn.next()).await? {
@ -560,7 +565,7 @@ impl Client {
bail!("Reset by the peer"); bail!("Reset by the peer");
} }
} }
Ok(()) Ok(option_pk)
} }
/// Request a relay connection to the server. /// Request a relay connection to the server.

View File

@ -121,9 +121,11 @@ impl<T: InvokeUiSession> Remote<T> {
) )
.await .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_type(peer.is_secured(), direct); // flutter -> connection_ready
self.handler.set_connection_info(direct, false); self.handler.set_connection_info(direct, false);
self.handler
.set_fingerprint(crate::common::pk_to_fingerprint(pk.unwrap_or_default()));
// just build for now // just build for now
#[cfg(not(windows))] #[cfg(not(windows))]

View File

@ -840,3 +840,17 @@ pub fn is_peer_version_ge(v: &str) -> bool {
false false
} }
pub fn pk_to_fingerprint(pk: Vec<u8>) -> 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()
}

View File

@ -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) { fn job_error(&self, id: i32, err: String, file_num: i32) {
self.push_event( self.push_event(
"job_error", "job_error",

View File

@ -921,6 +921,10 @@ pub fn main_get_permanent_password() -> String {
ui_interface::permanent_password() ui_interface::permanent_password()
} }
pub fn main_get_fingerprint() -> String {
get_fingerprint()
}
pub fn main_get_online_statue() -> i64 { pub fn main_get_online_statue() -> i64 {
ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone() ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone()
} }

View File

@ -383,6 +383,12 @@ async fn handle(data: Data, stream: &mut Connection) {
)); ));
} else if name == "rendezvous_servers" { } else if name == "rendezvous_servers" {
value = Some(Config::get_rendezvous_servers().join(",")); 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 { } else {
value = None; 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<()> { pub fn set_permanent_password(v: String) -> ResultType<()> {
Config::set_permanent_password(&v); Config::set_permanent_password(&v);
set_config("permanent-password", v) set_config("permanent-password", v)

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", "desktop 未安装"), ("no_desktop_title_tip", "desktop 未安装"),
("no_desktop_text_tip", "请安装 desktop"), ("no_desktop_text_tip", "请安装 desktop"),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", "指纹"),
("Copy Fingerprint", "复制指纹"),
("no fingerprints", "没有指纹"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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_title_tip", "Es ist kein Desktop verfügbar."),
("no_desktop_text_tip", "Bitte installieren Sie den GNOME-Desktop."), ("no_desktop_text_tip", "Bitte installieren Sie den GNOME-Desktop."),
("No need to elevate", "Erhöhung der Rechte nicht erforderlich"), ("No need to elevate", "Erhöhung der Rechte nicht erforderlich"),
("System Sound", ""),
("Default", ""),
("New RDP", "Neue RDP-Verbindung"), ("New RDP", "Neue RDP-Verbindung"),
("Failed to listen on {}: {}", "Lauschen fehlgeschlagen auf Port {}: {}"), ("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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_title_tip", "No hay escritorio disponible"),
("no_desktop_text_tip", "Por favor, instala GNOME Desktop"), ("no_desktop_text_tip", "Por favor, instala GNOME Desktop"),
("No need to elevate", "No es necesario elevar privilegios"), ("No need to elevate", "No es necesario elevar privilegios"),
("System Sound", ""),
("Default", ""),
("New RDP", "Nuevo RDP"), ("New RDP", "Nuevo RDP"),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", "هیچ دسکتاپی در دسترس نیست"), ("no_desktop_title_tip", "هیچ دسکتاپی در دسترس نیست"),
("no_desktop_text_tip", "لطفا دسکتاپ گنوم را نصب کنید"), ("no_desktop_text_tip", "لطفا دسکتاپ گنوم را نصب کنید"),
("No need to elevate", "نیازی به ارتقاء نیست"), ("No need to elevate", "نیازی به ارتقاء نیست"),
("System Sound", ""),
("Default", ""),
("New RDP", "ریموت جدید"), ("New RDP", "ریموت جدید"),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -495,5 +495,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("System Sound", "Dispositivo audio sistema"), ("System Sound", "Dispositivo audio sistema"),
("Default", "Predefinita"), ("Default", "Predefinita"),
("New RDP", "Nuovo RDP"), ("New RDP", "Nuovo RDP"),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -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_title_tip", "Nėra pasiekiamų nuotolinių darbalaukių"),
("no_desktop_text_tip", "Prašom įdiegti GNOME Desktop"), ("no_desktop_text_tip", "Prašom įdiegti GNOME Desktop"),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -495,5 +495,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("System Sound", "Dźwięk Systemowy"), ("System Sound", "Dźwięk Systemowy"),
("Default", "Domyślne"), ("Default", "Domyślne"),
("New RDP", "Nowe RDP"), ("New RDP", "Nowe RDP"),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", "Нет доступных рабочих столов"), ("no_desktop_title_tip", "Нет доступных рабочих столов"),
("no_desktop_text_tip", "Установите GNOME Desktop"), ("no_desktop_text_tip", "Установите GNOME Desktop"),
("No need to elevate", "Повышение прав не требуется"), ("No need to elevate", "Повышение прав не требуется"),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -495,5 +495,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("System Sound", ""), ("System Sound", ""),
("Default", ""), ("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", "沒有可用的桌面"), ("no_desktop_title_tip", "沒有可用的桌面"),
("no_desktop_text_tip", "請安裝 GNOME 桌面"), ("no_desktop_text_tip", "請安裝 GNOME 桌面"),
("No need to elevate", "不需要提升權限"), ("No need to elevate", "不需要提升權限"),
("System Sound", ""),
("Default", ""),
("New RDP", "新的 RDP"), ("New RDP", "新的 RDP"),
("Fingerprint", "指紋"),
("Copy Fingerprint", "複製指紋"),
("no fingerprints", "沒有指紋"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -492,6 +492,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("no_desktop_title_tip", ""), ("no_desktop_title_tip", ""),
("no_desktop_text_tip", ""), ("no_desktop_text_tip", ""),
("No need to elevate", ""), ("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""), ("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -154,7 +154,8 @@ async fn connect_and_login_2(
} else { } else {
ConnType::PORT_FORWARD 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 interface = interface;
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut received = false; let mut received = false;

View File

@ -470,6 +470,10 @@ impl UI {
get_version() get_version()
} }
fn get_fingerprint(&self) -> String {
get_fingerprint()
}
fn get_app_name(&self) -> String { fn get_app_name(&self) -> String {
get_app_name() get_app_name()
} }
@ -649,6 +653,7 @@ impl sciter::EventHandler for UI {
fn get_software_update_url(); fn get_software_update_url();
fn get_new_version(); fn get_new_version();
fn get_version(); fn get_version();
fn get_fingerprint();
fn update_me(String); fn update_me(String);
fn show_run_without_install(); fn show_run_without_install();
fn run_without_install(); fn run_without_install();

View File

@ -364,6 +364,7 @@ class MyIdMenu: Reactor.Component {
var name = handler.get_app_name(); var name = handler.get_app_name();
msgbox("custom-nocancel-nook-hasclose", translate("About") + " " + name, "<div style='line-height: 2em'> \ msgbox("custom-nocancel-nook-hasclose", translate("About") + " " + name, "<div style='line-height: 2em'> \
<div>Version: " + handler.get_version() + " \ <div>Version: " + handler.get_version() + " \
<div>Fingerprint: " + handler.get_fingerprint() + " \
<div .link .custom-event url='https://rustdesk.com/privacy'>Privacy Statement</div> \ <div .link .custom-event url='https://rustdesk.com/privacy'>Privacy Statement</div> \
<div .link .custom-event url='https://rustdesk.com'>Website</div> \ <div .link .custom-event url='https://rustdesk.com'>Website</div> \
<div style='background: #2c8cff; color: white; padding: 1em; margin-top: 1em;'>Copyright &copy; 2022 Purslane Ltd.\ <div style='background: #2c8cff; color: white; padding: 1em; margin-top: 1em;'>Copyright &copy; 2022 Purslane Ltd.\

View File

@ -144,6 +144,8 @@ impl InvokeUiSession for SciterHandler {
self.call("setConnectionType", &make_args!(is_secured, direct)); 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) { fn job_error(&self, id: i32, err: String, file_num: i32) {
self.call("jobError", &make_args!(id, err, file_num)); self.call("jobError", &make_args!(id, err, file_num));
} }

View File

@ -24,13 +24,12 @@ use hbb_common::{
rendezvous_proto::*, rendezvous_proto::*,
}; };
use crate::common::SOFTWARE_UPDATE_URL;
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
use crate::hbbs_http::account; use crate::hbbs_http::account;
use crate::{common::SOFTWARE_UPDATE_URL};
#[cfg(not(any(target_os = "ios")))] #[cfg(not(any(target_os = "ios")))]
use crate::ipc; use crate::ipc;
type Message = RendezvousMessage; type Message = RendezvousMessage;
pub type Children = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>; pub type Children = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>;
@ -515,8 +514,7 @@ pub fn get_error() -> String {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
let dtype = crate::platform::linux::get_display_server(); 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(); return crate::server::wayland::common_get_error();
} }
if dtype != crate::platform::linux::DISPLAY_SERVER_X11 { 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) 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, // notice: avoiding create ipc connection repeatedly,
// because windows named pipe has serious memory leak issue. // because windows named pipe has serious memory leak issue.
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]

View File

@ -889,6 +889,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn close_success(&self); fn close_success(&self);
fn update_quality_status(&self, qs: QualityStatus); fn update_quality_status(&self, qs: QualityStatus);
fn set_connection_type(&self, is_secured: bool, direct: bool); 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_error(&self, id: i32, err: String, file_num: i32);
fn job_done(&self, id: i32, file_num: i32); fn job_done(&self, id: i32, file_num: i32);
fn clear_all_jobs(&self); fn clear_all_jobs(&self);