no password required for file transfer action in remote control menu (#9731)
Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
parent
7a3e1fe648
commit
445e9ac285
@ -2304,16 +2304,19 @@ connectMainDesktop(String id,
|
|||||||
required bool isRDP,
|
required bool isRDP,
|
||||||
bool? forceRelay,
|
bool? forceRelay,
|
||||||
String? password,
|
String? password,
|
||||||
|
String? connToken,
|
||||||
bool? isSharedPassword}) async {
|
bool? isSharedPassword}) async {
|
||||||
if (isFileTransfer) {
|
if (isFileTransfer) {
|
||||||
await rustDeskWinManager.newFileTransfer(id,
|
await rustDeskWinManager.newFileTransfer(id,
|
||||||
password: password,
|
password: password,
|
||||||
isSharedPassword: isSharedPassword,
|
isSharedPassword: isSharedPassword,
|
||||||
|
connToken: connToken,
|
||||||
forceRelay: forceRelay);
|
forceRelay: forceRelay);
|
||||||
} else if (isTcpTunneling || isRDP) {
|
} else if (isTcpTunneling || isRDP) {
|
||||||
await rustDeskWinManager.newPortForward(id, isRDP,
|
await rustDeskWinManager.newPortForward(id, isRDP,
|
||||||
password: password,
|
password: password,
|
||||||
isSharedPassword: isSharedPassword,
|
isSharedPassword: isSharedPassword,
|
||||||
|
connToken: connToken,
|
||||||
forceRelay: forceRelay);
|
forceRelay: forceRelay);
|
||||||
} else {
|
} else {
|
||||||
await rustDeskWinManager.newRemoteDesktop(id,
|
await rustDeskWinManager.newRemoteDesktop(id,
|
||||||
@ -2333,6 +2336,7 @@ connect(BuildContext context, String id,
|
|||||||
bool isRDP = false,
|
bool isRDP = false,
|
||||||
bool forceRelay = false,
|
bool forceRelay = false,
|
||||||
String? password,
|
String? password,
|
||||||
|
String? connToken,
|
||||||
bool? isSharedPassword}) async {
|
bool? isSharedPassword}) async {
|
||||||
if (id == '') return;
|
if (id == '') return;
|
||||||
if (!isDesktop || desktopType == DesktopType.main) {
|
if (!isDesktop || desktopType == DesktopType.main) {
|
||||||
@ -2374,6 +2378,7 @@ connect(BuildContext context, String id,
|
|||||||
'password': password,
|
'password': password,
|
||||||
'isSharedPassword': isSharedPassword,
|
'isSharedPassword': isSharedPassword,
|
||||||
'forceRelay': forceRelay,
|
'forceRelay': forceRelay,
|
||||||
|
'connToken': connToken,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,12 +147,23 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
|||||||
child: Text(translate('Reset canvas')),
|
child: Text(translate('Reset canvas')),
|
||||||
onPressed: () => ffi.cursorModel.reset()));
|
onPressed: () => ffi.cursorModel.reset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectWithToken(
|
||||||
|
{required bool isFileTransfer, required bool isTcpTunneling}) {
|
||||||
|
final connToken = bind.sessionGetConnToken(sessionId: ffi.sessionId);
|
||||||
|
connect(context, id,
|
||||||
|
isFileTransfer: isFileTransfer,
|
||||||
|
isTcpTunneling: isTcpTunneling,
|
||||||
|
connToken: connToken);
|
||||||
|
}
|
||||||
|
|
||||||
// transferFile
|
// transferFile
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
v.add(
|
v.add(
|
||||||
TTextMenu(
|
TTextMenu(
|
||||||
child: Text(translate('Transfer file')),
|
child: Text(translate('Transfer file')),
|
||||||
onPressed: () => connect(context, id, isFileTransfer: true)),
|
onPressed: () =>
|
||||||
|
connectWithToken(isFileTransfer: true, isTcpTunneling: false)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// tcpTunneling
|
// tcpTunneling
|
||||||
@ -160,7 +171,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
|||||||
v.add(
|
v.add(
|
||||||
TTextMenu(
|
TTextMenu(
|
||||||
child: Text(translate('TCP tunneling')),
|
child: Text(translate('TCP tunneling')),
|
||||||
onPressed: () => connect(context, id, isTcpTunneling: true)),
|
onPressed: () =>
|
||||||
|
connectWithToken(isFileTransfer: false, isTcpTunneling: true)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// note
|
// note
|
||||||
|
@ -774,6 +774,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
|||||||
isRDP: call.arguments['isRDP'],
|
isRDP: call.arguments['isRDP'],
|
||||||
password: call.arguments['password'],
|
password: call.arguments['password'],
|
||||||
forceRelay: call.arguments['forceRelay'],
|
forceRelay: call.arguments['forceRelay'],
|
||||||
|
connToken: call.arguments['connToken'],
|
||||||
);
|
);
|
||||||
} else if (call.method == kWindowEventMoveTabToNewWindow) {
|
} else if (call.method == kWindowEventMoveTabToNewWindow) {
|
||||||
final args = call.arguments.split(',');
|
final args = call.arguments.split(',');
|
||||||
|
@ -58,12 +58,14 @@ class FileManagerPage extends StatefulWidget {
|
|||||||
required this.password,
|
required this.password,
|
||||||
required this.isSharedPassword,
|
required this.isSharedPassword,
|
||||||
this.tabController,
|
this.tabController,
|
||||||
|
this.connToken,
|
||||||
this.forceRelay})
|
this.forceRelay})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
final String id;
|
final String id;
|
||||||
final String? password;
|
final String? password;
|
||||||
final bool? isSharedPassword;
|
final bool? isSharedPassword;
|
||||||
final bool? forceRelay;
|
final bool? forceRelay;
|
||||||
|
final String? connToken;
|
||||||
final DesktopTabController? tabController;
|
final DesktopTabController? tabController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -90,6 +92,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
isFileTransfer: true,
|
isFileTransfer: true,
|
||||||
password: widget.password,
|
password: widget.password,
|
||||||
isSharedPassword: widget.isSharedPassword,
|
isSharedPassword: widget.isSharedPassword,
|
||||||
|
connToken: widget.connToken,
|
||||||
forceRelay: widget.forceRelay);
|
forceRelay: widget.forceRelay);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_ffi.dialogManager
|
_ffi.dialogManager
|
||||||
|
@ -48,6 +48,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
|||||||
isSharedPassword: params['isSharedPassword'],
|
isSharedPassword: params['isSharedPassword'],
|
||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
forceRelay: params['forceRelay'],
|
forceRelay: params['forceRelay'],
|
||||||
|
connToken: params['connToken'],
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
|
rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
|
||||||
print(
|
debugPrint(
|
||||||
"[FileTransfer] call ${call.method} with args ${call.arguments} from window $fromWindowId to ${windowId()}");
|
"[FileTransfer] call ${call.method} with args ${call.arguments} from window $fromWindowId to ${windowId()}");
|
||||||
// for simplify, just replace connectionId
|
// for simplify, just replace connectionId
|
||||||
if (call.method == kWindowEventNewFileTransfer) {
|
if (call.method == kWindowEventNewFileTransfer) {
|
||||||
@ -76,6 +77,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
|||||||
isSharedPassword: args['isSharedPassword'],
|
isSharedPassword: args['isSharedPassword'],
|
||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
forceRelay: args['forceRelay'],
|
forceRelay: args['forceRelay'],
|
||||||
|
connToken: args['connToken'],
|
||||||
)));
|
)));
|
||||||
} else if (call.method == "onDestroy") {
|
} else if (call.method == "onDestroy") {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
|
@ -33,6 +33,7 @@ class PortForwardPage extends StatefulWidget {
|
|||||||
required this.isRDP,
|
required this.isRDP,
|
||||||
required this.isSharedPassword,
|
required this.isSharedPassword,
|
||||||
this.forceRelay,
|
this.forceRelay,
|
||||||
|
this.connToken,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final String id;
|
final String id;
|
||||||
final String? password;
|
final String? password;
|
||||||
@ -40,6 +41,7 @@ class PortForwardPage extends StatefulWidget {
|
|||||||
final bool isRDP;
|
final bool isRDP;
|
||||||
final bool? forceRelay;
|
final bool? forceRelay;
|
||||||
final bool? isSharedPassword;
|
final bool? isSharedPassword;
|
||||||
|
final String? connToken;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<PortForwardPage> createState() => _PortForwardPageState();
|
State<PortForwardPage> createState() => _PortForwardPageState();
|
||||||
@ -62,6 +64,7 @@ class _PortForwardPageState extends State<PortForwardPage>
|
|||||||
password: widget.password,
|
password: widget.password,
|
||||||
isSharedPassword: widget.isSharedPassword,
|
isSharedPassword: widget.isSharedPassword,
|
||||||
forceRelay: widget.forceRelay,
|
forceRelay: widget.forceRelay,
|
||||||
|
connToken: widget.connToken,
|
||||||
isRdp: widget.isRDP);
|
isRdp: widget.isRDP);
|
||||||
Get.put<FFI>(_ffi, tag: 'pf_${widget.id}');
|
Get.put<FFI>(_ffi, tag: 'pf_${widget.id}');
|
||||||
debugPrint("Port forward page init success with id ${widget.id}");
|
debugPrint("Port forward page init success with id ${widget.id}");
|
||||||
|
@ -48,6 +48,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
|||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
isRDP: isRDP,
|
isRDP: isRDP,
|
||||||
forceRelay: params['forceRelay'],
|
forceRelay: params['forceRelay'],
|
||||||
|
connToken: params['connToken'],
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +83,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
|||||||
isRDP: isRDP,
|
isRDP: isRDP,
|
||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
forceRelay: args['forceRelay'],
|
forceRelay: args['forceRelay'],
|
||||||
|
connToken: args['connToken'],
|
||||||
)));
|
)));
|
||||||
} else if (call.method == "onDestroy") {
|
} else if (call.method == "onDestroy") {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
|
@ -395,7 +395,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
RemoteCountState.find().value = tabController.length;
|
RemoteCountState.find().value = tabController.length;
|
||||||
|
|
||||||
Future<dynamic> _remoteMethodHandler(call, fromWindowId) async {
|
Future<dynamic> _remoteMethodHandler(call, fromWindowId) async {
|
||||||
print(
|
debugPrint(
|
||||||
"[Remote Page] call ${call.method} with args ${call.arguments} from window $fromWindowId");
|
"[Remote Page] call ${call.method} with args ${call.arguments} from window $fromWindowId");
|
||||||
|
|
||||||
dynamic returnValue;
|
dynamic returnValue;
|
||||||
|
@ -375,7 +375,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
} else if (name == 'plugin_option') {
|
} else if (name == 'plugin_option') {
|
||||||
handleOption(evt);
|
handleOption(evt);
|
||||||
} else if (name == "sync_peer_hash_password_to_personal_ab") {
|
} else if (name == "sync_peer_hash_password_to_personal_ab") {
|
||||||
if (desktopType == DesktopType.main || isWeb) {
|
if (desktopType == DesktopType.main || isWeb || isMobile) {
|
||||||
final id = evt['id'];
|
final id = evt['id'];
|
||||||
final hash = evt['hash'];
|
final hash = evt['hash'];
|
||||||
if (id != null && hash != null) {
|
if (id != null && hash != null) {
|
||||||
@ -2462,6 +2462,7 @@ class FFI {
|
|||||||
String? switchUuid,
|
String? switchUuid,
|
||||||
String? password,
|
String? password,
|
||||||
bool? isSharedPassword,
|
bool? isSharedPassword,
|
||||||
|
String? connToken,
|
||||||
bool? forceRelay,
|
bool? forceRelay,
|
||||||
int? tabWindowId,
|
int? tabWindowId,
|
||||||
int? display,
|
int? display,
|
||||||
@ -2498,6 +2499,7 @@ class FFI {
|
|||||||
forceRelay: forceRelay ?? false,
|
forceRelay: forceRelay ?? false,
|
||||||
password: password ?? '',
|
password: password ?? '',
|
||||||
isSharedPassword: isSharedPassword ?? false,
|
isSharedPassword: isSharedPassword ?? false,
|
||||||
|
connToken: connToken,
|
||||||
);
|
);
|
||||||
} else if (display != null) {
|
} else if (display != null) {
|
||||||
if (displays == null) {
|
if (displays == null) {
|
||||||
|
@ -201,6 +201,7 @@ class RustDeskMultiWindowManager {
|
|||||||
String? switchUuid,
|
String? switchUuid,
|
||||||
bool? isRDP,
|
bool? isRDP,
|
||||||
bool? isSharedPassword,
|
bool? isSharedPassword,
|
||||||
|
String? connToken,
|
||||||
}) async {
|
}) async {
|
||||||
var params = {
|
var params = {
|
||||||
"type": type.index,
|
"type": type.index,
|
||||||
@ -217,6 +218,9 @@ class RustDeskMultiWindowManager {
|
|||||||
if (isSharedPassword != null) {
|
if (isSharedPassword != null) {
|
||||||
params['isSharedPassword'] = isSharedPassword;
|
params['isSharedPassword'] = isSharedPassword;
|
||||||
}
|
}
|
||||||
|
if (connToken != null) {
|
||||||
|
params['connToken'] = connToken;
|
||||||
|
}
|
||||||
final msg = jsonEncode(params);
|
final msg = jsonEncode(params);
|
||||||
|
|
||||||
// separate window for file transfer is not supported
|
// separate window for file transfer is not supported
|
||||||
@ -254,8 +258,13 @@ class RustDeskMultiWindowManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<MultiWindowCallResult> newFileTransfer(String remoteId,
|
Future<MultiWindowCallResult> newFileTransfer(
|
||||||
{String? password, bool? isSharedPassword, bool? forceRelay}) async {
|
String remoteId, {
|
||||||
|
String? password,
|
||||||
|
bool? isSharedPassword,
|
||||||
|
bool? forceRelay,
|
||||||
|
String? connToken,
|
||||||
|
}) async {
|
||||||
return await newSession(
|
return await newSession(
|
||||||
WindowType.FileTransfer,
|
WindowType.FileTransfer,
|
||||||
kWindowEventNewFileTransfer,
|
kWindowEventNewFileTransfer,
|
||||||
@ -264,11 +273,18 @@ class RustDeskMultiWindowManager {
|
|||||||
password: password,
|
password: password,
|
||||||
forceRelay: forceRelay,
|
forceRelay: forceRelay,
|
||||||
isSharedPassword: isSharedPassword,
|
isSharedPassword: isSharedPassword,
|
||||||
|
connToken: connToken,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<MultiWindowCallResult> newPortForward(String remoteId, bool isRDP,
|
Future<MultiWindowCallResult> newPortForward(
|
||||||
{String? password, bool? isSharedPassword, bool? forceRelay}) async {
|
String remoteId,
|
||||||
|
bool isRDP, {
|
||||||
|
String? password,
|
||||||
|
bool? isSharedPassword,
|
||||||
|
bool? forceRelay,
|
||||||
|
String? connToken,
|
||||||
|
}) async {
|
||||||
return await newSession(
|
return await newSession(
|
||||||
WindowType.PortForward,
|
WindowType.PortForward,
|
||||||
kWindowEventNewPortForward,
|
kWindowEventNewPortForward,
|
||||||
@ -278,6 +294,7 @@ class RustDeskMultiWindowManager {
|
|||||||
forceRelay: forceRelay,
|
forceRelay: forceRelay,
|
||||||
isRDP: isRDP,
|
isRDP: isRDP,
|
||||||
isSharedPassword: isSharedPassword,
|
isSharedPassword: isSharedPassword,
|
||||||
|
connToken: connToken,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use crossbeam_queue::ArrayQueue;
|
|||||||
use magnum_opus::{Channels::*, Decoder as AudioDecoder};
|
use magnum_opus::{Channels::*, Decoder as AudioDecoder};
|
||||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||||
use ringbuf::{ring_buffer::RbBase, Rb};
|
use ringbuf::{ring_buffer::RbBase, Rb};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -1274,7 +1275,7 @@ impl VideoHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The source of sent password
|
// The source of sent password
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
enum PasswordSource {
|
enum PasswordSource {
|
||||||
PersonalAb(Vec<u8>),
|
PersonalAb(Vec<u8>),
|
||||||
SharedAb(String),
|
SharedAb(String),
|
||||||
@ -1320,6 +1321,13 @@ impl PasswordSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
struct ConnToken {
|
||||||
|
password: Vec<u8>,
|
||||||
|
password_source: PasswordSource,
|
||||||
|
session_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// Login config handler for [`Client`].
|
/// Login config handler for [`Client`].
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LoginConfigHandler {
|
pub struct LoginConfigHandler {
|
||||||
@ -1376,6 +1384,7 @@ impl LoginConfigHandler {
|
|||||||
mut force_relay: bool,
|
mut force_relay: bool,
|
||||||
adapter_luid: Option<i64>,
|
adapter_luid: Option<i64>,
|
||||||
shared_password: Option<String>,
|
shared_password: Option<String>,
|
||||||
|
conn_token: Option<String>,
|
||||||
) {
|
) {
|
||||||
let mut id = id;
|
let mut id = id;
|
||||||
if id.contains("@") {
|
if id.contains("@") {
|
||||||
@ -1419,11 +1428,23 @@ impl LoginConfigHandler {
|
|||||||
let config = self.load_config();
|
let config = self.load_config();
|
||||||
self.remember = !config.password.is_empty();
|
self.remember = !config.password.is_empty();
|
||||||
self.config = config;
|
self.config = config;
|
||||||
let mut sid = rand::random();
|
|
||||||
|
let conn_token = conn_token
|
||||||
|
.map(|x| serde_json::from_str::<ConnToken>(&x).ok())
|
||||||
|
.flatten();
|
||||||
|
let mut sid = 0;
|
||||||
|
if let Some(token) = conn_token {
|
||||||
|
sid = token.session_id;
|
||||||
|
self.password = token.password; // use as last password
|
||||||
|
self.password_source = token.password_source;
|
||||||
|
}
|
||||||
|
if sid == 0 {
|
||||||
|
sid = rand::random();
|
||||||
if sid == 0 {
|
if sid == 0 {
|
||||||
// you won the lottery
|
// you won the lottery
|
||||||
sid = 1;
|
sid = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.session_id = sid;
|
self.session_id = sid;
|
||||||
self.supported_encoding = Default::default();
|
self.supported_encoding = Default::default();
|
||||||
self.restarting_remote_device = false;
|
self.restarting_remote_device = false;
|
||||||
@ -2223,6 +2244,18 @@ impl LoginConfigHandler {
|
|||||||
msg_out.set_misc(misc);
|
msg_out.set_misc(misc);
|
||||||
msg_out
|
msg_out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_conn_token(&self) -> Option<String> {
|
||||||
|
if self.password.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
serde_json::to_string(&ConnToken {
|
||||||
|
password: self.password.clone(),
|
||||||
|
password_source: self.password_source.clone(),
|
||||||
|
session_id: self.session_id,
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Media data.
|
/// Media data.
|
||||||
|
@ -1126,6 +1126,7 @@ pub fn session_add(
|
|||||||
force_relay: bool,
|
force_relay: bool,
|
||||||
password: String,
|
password: String,
|
||||||
is_shared_password: bool,
|
is_shared_password: bool,
|
||||||
|
conn_token: Option<String>,
|
||||||
) -> ResultType<FlutterSession> {
|
) -> ResultType<FlutterSession> {
|
||||||
let conn_type = if is_file_transfer {
|
let conn_type = if is_file_transfer {
|
||||||
ConnType::FILE_TRANSFER
|
ConnType::FILE_TRANSFER
|
||||||
@ -1180,6 +1181,7 @@ pub fn session_add(
|
|||||||
force_relay,
|
force_relay,
|
||||||
get_adapter_luid(),
|
get_adapter_luid(),
|
||||||
shared_password,
|
shared_password,
|
||||||
|
conn_token,
|
||||||
);
|
);
|
||||||
|
|
||||||
let session = Arc::new(session.clone());
|
let session = Arc::new(session.clone());
|
||||||
|
@ -121,6 +121,7 @@ pub fn session_add_sync(
|
|||||||
force_relay: bool,
|
force_relay: bool,
|
||||||
password: String,
|
password: String,
|
||||||
is_shared_password: bool,
|
is_shared_password: bool,
|
||||||
|
conn_token: Option<String>,
|
||||||
) -> SyncReturn<String> {
|
) -> SyncReturn<String> {
|
||||||
if let Err(e) = session_add(
|
if let Err(e) = session_add(
|
||||||
&session_id,
|
&session_id,
|
||||||
@ -132,6 +133,7 @@ pub fn session_add_sync(
|
|||||||
force_relay,
|
force_relay,
|
||||||
password,
|
password,
|
||||||
is_shared_password,
|
is_shared_password,
|
||||||
|
conn_token,
|
||||||
) {
|
) {
|
||||||
SyncReturn(format!("Failed to add session with id {}, {}", &id, e))
|
SyncReturn(format!("Failed to add session with id {}, {}", &id, e))
|
||||||
} else {
|
} else {
|
||||||
@ -1341,6 +1343,14 @@ pub fn session_close_voice_call(session_id: SessionID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn session_get_conn_token(session_id: SessionID) -> SyncReturn<Option<String>> {
|
||||||
|
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||||
|
SyncReturn(session.get_conn_token())
|
||||||
|
} else {
|
||||||
|
SyncReturn(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cm_handle_incoming_voice_call(id: i32, accept: bool) {
|
pub fn cm_handle_incoming_voice_call(id: i32, accept: bool) {
|
||||||
crate::ui_cm_interface::handle_incoming_voice_call(id, accept);
|
crate::ui_cm_interface::handle_incoming_voice_call(id, accept);
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,9 @@ pub type Sender = mpsc::UnboundedSender<(Instant, Arc<Message>)>;
|
|||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref LOGIN_FAILURES: [Arc::<Mutex<HashMap<String, (i32, i32, i32)>>>; 2] = Default::default();
|
static ref LOGIN_FAILURES: [Arc::<Mutex<HashMap<String, (i32, i32, i32)>>>; 2] = Default::default();
|
||||||
static ref SESSIONS: Arc::<Mutex<HashMap<String, Session>>> = Default::default();
|
static ref SESSIONS: Arc::<Mutex<HashMap<SessionKey, Session>>> = Default::default();
|
||||||
static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default();
|
static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default();
|
||||||
pub static ref AUTHED_CONNS: Arc::<Mutex<Vec<(i32, AuthConnType)>>> = Default::default();
|
pub static ref AUTHED_CONNS: Arc::<Mutex<Vec<(i32, AuthConnType, SessionKey)>>> = Default::default();
|
||||||
static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default();
|
static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default();
|
||||||
static ref WAKELOCK_SENDER: Arc::<Mutex<std::sync::mpsc::Sender<(usize, usize)>>> = Arc::new(Mutex::new(start_wakelock_thread()));
|
static ref WAKELOCK_SENDER: Arc::<Mutex<std::sync::mpsc::Sender<(usize, usize)>>> = Arc::new(Mutex::new(start_wakelock_thread()));
|
||||||
}
|
}
|
||||||
@ -140,13 +140,20 @@ enum MessageInput {
|
|||||||
BlockOffPlugin(String),
|
BlockOffPlugin(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
struct Session {
|
pub struct SessionKey {
|
||||||
|
peer_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
session_id: u64,
|
session_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Session {
|
||||||
last_recv_time: Arc<Mutex<Instant>>,
|
last_recv_time: Arc<Mutex<Instant>>,
|
||||||
random_password: String,
|
random_password: String,
|
||||||
tfa: bool,
|
tfa: bool,
|
||||||
|
conn_type: AuthConnType,
|
||||||
|
conn_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
@ -1131,6 +1138,7 @@ impl Connection {
|
|||||||
self.authed_conn_id = Some(self::raii::AuthedConnID::new(
|
self.authed_conn_id = Some(self::raii::AuthedConnID::new(
|
||||||
self.inner.id(),
|
self.inner.id(),
|
||||||
auth_conn_type,
|
auth_conn_type,
|
||||||
|
self.session_key(),
|
||||||
));
|
));
|
||||||
self.post_conn_audit(
|
self.post_conn_audit(
|
||||||
json!({"peer": ((&self.lr.my_id, &self.lr.my_name)), "type": conn_type}),
|
json!({"peer": ((&self.lr.my_id, &self.lr.my_name)), "type": conn_type}),
|
||||||
@ -1541,14 +1549,14 @@ impl Connection {
|
|||||||
if password::temporary_enabled() {
|
if password::temporary_enabled() {
|
||||||
let password = password::temporary_password();
|
let password = password::temporary_password();
|
||||||
if self.validate_one_password(password.clone()) {
|
if self.validate_one_password(password.clone()) {
|
||||||
SESSIONS.lock().unwrap().insert(
|
raii::AuthedConnID::insert_session(
|
||||||
self.lr.my_id.clone(),
|
self.session_key(),
|
||||||
Session {
|
Session {
|
||||||
name: self.lr.my_name.clone(),
|
|
||||||
session_id: self.lr.session_id,
|
|
||||||
last_recv_time: self.last_recv_time.clone(),
|
last_recv_time: self.last_recv_time.clone(),
|
||||||
random_password: password,
|
random_password: password,
|
||||||
tfa: false,
|
tfa: false,
|
||||||
|
conn_type: self.conn_type(),
|
||||||
|
conn_id: self.inner.id(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@ -1570,21 +1578,19 @@ impl Connection {
|
|||||||
let session = SESSIONS
|
let session = SESSIONS
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(&self.lr.my_id)
|
.get(&self.session_key())
|
||||||
.map(|s| s.to_owned());
|
.map(|s| s.to_owned());
|
||||||
// last_recv_time is a mutex variable shared with connection, can be updated lively.
|
// last_recv_time is a mutex variable shared with connection, can be updated lively.
|
||||||
if let Some(mut session) = session {
|
if let Some(mut session) = session {
|
||||||
if session.name == self.lr.my_name
|
if !self.lr.password.is_empty()
|
||||||
&& session.session_id == self.lr.session_id
|
|
||||||
&& !self.lr.password.is_empty()
|
|
||||||
&& (tfa && session.tfa
|
&& (tfa && session.tfa
|
||||||
|| !tfa && self.validate_one_password(session.random_password.clone()))
|
|| !tfa && self.validate_one_password(session.random_password.clone()))
|
||||||
{
|
{
|
||||||
session.last_recv_time = self.last_recv_time.clone();
|
session.last_recv_time = self.last_recv_time.clone();
|
||||||
SESSIONS
|
session.conn_id = self.inner.id();
|
||||||
.lock()
|
session.conn_type = self.conn_type();
|
||||||
.unwrap()
|
raii::AuthedConnID::insert_session(self.session_key(), session);
|
||||||
.insert(self.lr.my_id.clone(), session);
|
log::info!("is recent session");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1844,23 +1850,22 @@ impl Connection {
|
|||||||
let session = SESSIONS
|
let session = SESSIONS
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(&self.lr.my_id)
|
.get(&self.session_key())
|
||||||
.map(|s| s.to_owned());
|
.map(|s| s.to_owned());
|
||||||
if let Some(mut session) = session {
|
if let Some(mut session) = session {
|
||||||
session.tfa = true;
|
session.tfa = true;
|
||||||
SESSIONS
|
session.conn_id = self.inner.id();
|
||||||
.lock()
|
session.conn_type = self.conn_type();
|
||||||
.unwrap()
|
raii::AuthedConnID::insert_session(self.session_key(), session);
|
||||||
.insert(self.lr.my_id.clone(), session);
|
|
||||||
} else {
|
} else {
|
||||||
SESSIONS.lock().unwrap().insert(
|
raii::AuthedConnID::insert_session(
|
||||||
self.lr.my_id.clone(),
|
self.session_key(),
|
||||||
Session {
|
Session {
|
||||||
name: self.lr.my_name.clone(),
|
|
||||||
session_id: self.lr.session_id,
|
|
||||||
last_recv_time: self.last_recv_time.clone(),
|
last_recv_time: self.last_recv_time.clone(),
|
||||||
random_password: "".to_owned(),
|
random_password: "".to_owned(),
|
||||||
tfa: true,
|
tfa: true,
|
||||||
|
conn_type: self.conn_type(),
|
||||||
|
conn_id: self.inner.id(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2159,11 +2164,7 @@ impl Connection {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if let Some(job_id) = job_id {
|
if let Some(job_id) = job_id {
|
||||||
self.send(fs::new_error(
|
self.send(fs::new_error(job_id, "one-way-file-transfer-tip", 0))
|
||||||
job_id,
|
|
||||||
"one-way-file-transfer-tip",
|
|
||||||
0,
|
|
||||||
))
|
|
||||||
.await;
|
.await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2399,7 +2400,10 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
Some(misc::Union::CloseReason(_)) => {
|
Some(misc::Union::CloseReason(_)) => {
|
||||||
self.on_close("Peer close", true).await;
|
self.on_close("Peer close", true).await;
|
||||||
SESSIONS.lock().unwrap().remove(&self.lr.my_id);
|
raii::AuthedConnID::remove_session_if_last_duplication(
|
||||||
|
self.inner.id(),
|
||||||
|
self.session_key(),
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3159,7 +3163,7 @@ impl Connection {
|
|||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_misc(misc);
|
msg_out.set_misc(misc);
|
||||||
self.send(msg_out).await;
|
self.send(msg_out).await;
|
||||||
SESSIONS.lock().unwrap().remove(&self.lr.my_id);
|
raii::AuthedConnID::remove_session_if_last_duplication(self.inner.id(), self.session_key());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_dir(&mut self, dir: &str, include_hidden: bool) {
|
fn read_dir(&mut self, dir: &str, include_hidden: bool) {
|
||||||
@ -3313,6 +3317,26 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn conn_type(&self) -> AuthConnType {
|
||||||
|
if self.file_transfer.is_some() {
|
||||||
|
AuthConnType::FileTransfer
|
||||||
|
} else if self.port_forward_socket.is_some() {
|
||||||
|
AuthConnType::PortForward
|
||||||
|
} else {
|
||||||
|
AuthConnType::Remote
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn session_key(&self) -> SessionKey {
|
||||||
|
SessionKey {
|
||||||
|
peer_id: self.lr.my_id.clone(),
|
||||||
|
name: self.lr.my_name.clone(),
|
||||||
|
session_id: self.lr.session_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
||||||
@ -3810,15 +3834,18 @@ mod raii {
|
|||||||
pub struct AuthedConnID(i32, AuthConnType);
|
pub struct AuthedConnID(i32, AuthConnType);
|
||||||
|
|
||||||
impl AuthedConnID {
|
impl AuthedConnID {
|
||||||
pub fn new(id: i32, conn_type: AuthConnType) -> Self {
|
pub fn new(conn_id: i32, conn_type: AuthConnType, session_key: SessionKey) -> Self {
|
||||||
AUTHED_CONNS.lock().unwrap().push((id, conn_type));
|
AUTHED_CONNS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push((conn_id, conn_type, session_key));
|
||||||
Self::check_wake_lock();
|
Self::check_wake_lock();
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
static _ONCE: Once = Once::new();
|
static _ONCE: Once = Once::new();
|
||||||
_ONCE.call_once(|| {
|
_ONCE.call_once(|| {
|
||||||
shutdown_hooks::add_shutdown_hook(connection_shutdown_hook);
|
shutdown_hooks::add_shutdown_hook(connection_shutdown_hook);
|
||||||
});
|
});
|
||||||
Self(id, conn_type)
|
Self(conn_id, conn_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_wake_lock() {
|
fn check_wake_lock() {
|
||||||
@ -3843,6 +3870,53 @@ mod raii {
|
|||||||
.filter(|c| c.1 == AuthConnType::Remote || c.1 == AuthConnType::FileTransfer)
|
.filter(|c| c.1 == AuthConnType::Remote || c.1 == AuthConnType::FileTransfer)
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_session_if_last_duplication(conn_id: i32, key: SessionKey) {
|
||||||
|
let contains = SESSIONS.lock().unwrap().contains_key(&key);
|
||||||
|
if contains {
|
||||||
|
let another = AUTHED_CONNS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.any(|c| c.0 != conn_id && c.2 == key && c.1 != AuthConnType::PortForward);
|
||||||
|
if !another {
|
||||||
|
// Keep the session if there is another connection with same peer_id and session_id.
|
||||||
|
SESSIONS.lock().unwrap().remove(&key);
|
||||||
|
log::info!("remove session");
|
||||||
|
} else {
|
||||||
|
log::info!("skip remove session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_session(key: SessionKey, session: Session) {
|
||||||
|
let mut insert = true;
|
||||||
|
if session.conn_type == AuthConnType::PortForward {
|
||||||
|
// port forward doesn't update last received time
|
||||||
|
let other_alive_conns = AUTHED_CONNS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|c| {
|
||||||
|
c.2 == key && c.1 != AuthConnType::PortForward // port forward doesn't remove itself
|
||||||
|
})
|
||||||
|
.map(|c| c.0)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let another = SESSIONS.lock().unwrap().get(&key).map(|s| {
|
||||||
|
other_alive_conns.contains(&s.conn_id)
|
||||||
|
&& s.tfa == session.tfa
|
||||||
|
&& s.conn_type != AuthConnType::PortForward
|
||||||
|
}) == Some(true);
|
||||||
|
if another {
|
||||||
|
insert = false;
|
||||||
|
log::info!("skip insert session for port forward");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if insert {
|
||||||
|
log::info!("insert session for {:?}", session.conn_type);
|
||||||
|
SESSIONS.lock().unwrap().insert(key, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for AuthedConnID {
|
impl Drop for AuthedConnID {
|
||||||
@ -3850,7 +3924,7 @@ mod raii {
|
|||||||
if self.1 == AuthConnType::Remote {
|
if self.1 == AuthConnType::Remote {
|
||||||
scrap::codec::Encoder::update(scrap::codec::EncodingUpdate::Remove(self.0));
|
scrap::codec::Encoder::update(scrap::codec::EncodingUpdate::Remove(self.0));
|
||||||
}
|
}
|
||||||
AUTHED_CONNS.lock().unwrap().retain(|&c| c.0 != self.0);
|
AUTHED_CONNS.lock().unwrap().retain(|c| c.0 != self.0);
|
||||||
let remote_count = AUTHED_CONNS
|
let remote_count = AUTHED_CONNS
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -506,7 +506,7 @@ impl sciter::EventHandler for SciterSession {
|
|||||||
impl SciterSession {
|
impl SciterSession {
|
||||||
pub fn new(cmd: String, id: String, password: String, args: Vec<String>) -> Self {
|
pub fn new(cmd: String, id: String, password: String, args: Vec<String>) -> Self {
|
||||||
let force_relay = args.contains(&"--relay".to_string());
|
let force_relay = args.contains(&"--relay".to_string());
|
||||||
let mut session: Session<SciterHandler> = Session {
|
let session: Session<SciterHandler> = Session {
|
||||||
password: password.clone(),
|
password: password.clone(),
|
||||||
args,
|
args,
|
||||||
server_keyboard_enabled: Arc::new(RwLock::new(true)),
|
server_keyboard_enabled: Arc::new(RwLock::new(true)),
|
||||||
@ -529,7 +529,7 @@ impl SciterSession {
|
|||||||
.lc
|
.lc
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.initialize(id, conn_type, None, force_relay, None, None);
|
.initialize(id, conn_type, None, force_relay, None, None, None);
|
||||||
|
|
||||||
Self(session)
|
Self(session)
|
||||||
}
|
}
|
||||||
|
@ -1490,6 +1490,10 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
msg.set_misc(misc);
|
msg.set_misc(misc);
|
||||||
self.send(Data::Message(msg));
|
self.send(Data::Message(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_conn_token(&self) -> Option<String> {
|
||||||
|
self.lc.read().unwrap().get_conn_token()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user