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),
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"));
}
}

View File

@ -121,6 +121,29 @@ class ConnectionTypeState {
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 {
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');
}

View File

@ -201,6 +201,13 @@ List<TTextMenu> 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;
}

View File

@ -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');

View File

@ -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<ConnectionTabPage> {
],
);
} 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<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>(
items: menu
.map((entry) => entry.build(

View File

@ -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<SettingsPage> with WidgetsBindingObserver {
var _autoRecordIncomingSession = false;
var _localIP = "";
var _directAccessPort = "";
var _fingerprint = "";
@override
void initState() {
@ -135,6 +137,12 @@ class _SettingsState extends State<SettingsPage> 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<SettingsPage> 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)),
],
),
],

View File

@ -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");
}

View File

@ -200,7 +200,7 @@ impl Client {
token: &str,
conn_type: ConnType,
interface: impl Interface,
) -> ResultType<(Stream, bool)> {
) -> ResultType<(Stream, bool, Option<Vec<u8>>)> {
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<Vec<u8>>)> {
// 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<Vec<u8>>)> {
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<Option<Vec<u8>>> {
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.

View File

@ -121,9 +121,11 @@ impl<T: InvokeUiSession> Remote<T> {
)
.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))]

View File

@ -840,3 +840,17 @@ pub fn is_peer_version_ge(v: &str) -> bool {
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) {
self.push_event(
"job_error",

View File

@ -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()
}

View File

@ -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)

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

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_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();
}

View File

@ -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();
}

View File

@ -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();
}

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_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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

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_text_tip", "Prašom įdiegti GNOME Desktop"),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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"),
("Default", "Domyślne"),
("New RDP", "Nowe RDP"),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", "Установите GNOME Desktop"),
("No need to elevate", "Повышение прав не требуется"),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].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_text_tip", ""),
("No need to elevate", ""),
("System Sound", ""),
("Default", ""),
("New RDP", ""),
("Fingerprint", ""),
("Copy Fingerprint", ""),
("no fingerprints", ""),
].iter().cloned().collect();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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();

View File

@ -364,6 +364,7 @@ class MyIdMenu: Reactor.Component {
var name = handler.get_app_name();
msgbox("custom-nocancel-nook-hasclose", translate("About") + " " + name, "<div style='line-height: 2em'> \
<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'>Website</div> \
<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));
}
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));
}

View File

@ -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<Mutex<(bool, HashMap<(String, String), Child>)>>;
@ -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")))]

View File

@ -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);