feat: request approval (#16784)

* feat: add connections without sending passwords

Add Without password actions and pass the selection through desktop,
mobile and Web sessions. Omit the password when constructing LoginRequest,
preserve saved credentials, and reuse the existing approval and OS login
dialogs. Keep protocol and controlled-side authentication changes separate.

* fix: preserve login method across session windows

* fix: skip password persistence for consent connections

* refactor: unify request approval menus and naming

* chore: move request approval translation key to the end

* i18n: translate request approval menu label

* fix: align request approval menu layout and icons

* fix: avoid duplicate focus stops in request approval menus

* fix: distinguish request approval submenus on mobile

* fix: open overflowing submenus to the left

* Revert "fix: distinguish request approval submenus on mobile"

This reverts commit 7f0e50d4e4.
This commit is contained in:
21pages authored and GitHub committed 2026-11-02 23:48:27 +08:00
1 parent 037b8787fe
commit a85ad89ffc
89 files changed
+1110 -152

No files matched your search

+44 -4
View File
@@ -2286,6 +2286,7 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
String? password;
String? switchUuid;
bool? forceRelay;
var loginMethod = '';
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case '--connect':
@@ -2329,6 +2330,9 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
password = args[i + 1];
i++;
break;
case '--request-approval':
loginMethod = 'request-approval';
break;
case '--switch_uuid':
switchUuid = args[i + 1];
i++;
@@ -2340,11 +2344,15 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
break;
}
}
if (loginMethod == 'request-approval') {
password = null;
}
if (type != null && id != null) {
switch (type) {
case UriLinkType.remoteDesktop:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newRemoteDesktop(id!,
loginMethod: loginMethod,
password: password,
switchUuid: switchUuid,
forceRelay: forceRelay);
@@ -2353,30 +2361,35 @@ bool handleUriLink({List<String>? cmdArgs, Uri? uri, String? uriString}) {
case UriLinkType.fileTransfer:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newFileTransfer(id!,
loginMethod: loginMethod,
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.viewCamera:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newViewCamera(id!,
loginMethod: loginMethod,
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.portForward:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newPortForward(id!, false,
loginMethod: loginMethod,
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.rdp:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newPortForward(id!, true,
loginMethod: loginMethod,
password: password, forceRelay: forceRelay);
});
break;
case UriLinkType.terminal:
Future.delayed(Duration.zero, () {
rustDeskWinManager.newTerminal(id!,
loginMethod: loginMethod,
password: password, forceRelay: forceRelay);
});
break;
@@ -2473,6 +2486,10 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
var queryParameters =
uri.queryParameters.map((k, v) => MapEntry(k.toLowerCase(), v));
final requestApproval = queryParameters['request-approval'] == 'true';
if (requestApproval) {
queryParameters.remove('password');
}
var key = queryParameters["key"];
if (id != null) {
@@ -2484,24 +2501,30 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
if (isMobile && id != null) {
final forceRelay = queryParameters["relay"] != null;
final password = queryParameters["password"];
final loginMethod = requestApproval ? 'request-approval' : '';
// Determine connection type based on command
if (command == '--file-transfer') {
connect(Get.context!, id,
loginMethod: loginMethod,
isFileTransfer: true, forceRelay: forceRelay, password: password);
} else if (command == '--view-camera') {
connect(Get.context!, id,
loginMethod: loginMethod,
isViewCamera: true, forceRelay: forceRelay, password: password);
} else if (command == '--terminal') {
connect(Get.context!, id,
loginMethod: loginMethod,
isTerminal: true, forceRelay: forceRelay, password: password);
} else if (command == 'terminal-admin') {
} else if (command == '--terminal-admin') {
setEnvTerminalAdmin();
connect(Get.context!, id,
loginMethod: loginMethod,
isTerminal: true, forceRelay: forceRelay, password: password);
} else {
// Default to remote desktop for '--connect', '--play', or direct connection
connect(Get.context!, id, forceRelay: forceRelay, password: password);
connect(Get.context!, id,
loginMethod: loginMethod, forceRelay: forceRelay, password: password);
}
return null;
}
@@ -2513,6 +2536,7 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
var param = queryParameters;
String? password = param["password"];
if (password != null) args.addAll(['--password', password]);
if (requestApproval) args.add('--request-approval');
String? switch_uuid = param["switch_uuid"];
if (switch_uuid != null) args.addAll(['--switch_uuid', switch_uuid]);
if (param["relay"] != null) args.add("--relay");
@@ -2531,33 +2555,39 @@ connectMainDesktop(String id,
bool? forceRelay,
String? password,
String? connToken,
bool? isSharedPassword}) async {
bool? isSharedPassword,
String loginMethod = ''}) async {
if (isFileTransfer) {
await rustDeskWinManager.newFileTransfer(id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else if (isViewCamera) {
await rustDeskWinManager.newViewCamera(id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else if (isTcpTunneling || isRDP) {
await rustDeskWinManager.newPortForward(id, isRDP,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else if (isTerminal) {
await rustDeskWinManager.newTerminal(id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
connToken: connToken,
forceRelay: forceRelay);
} else {
await rustDeskWinManager.newRemoteDesktop(id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay);
@@ -2578,7 +2608,8 @@ connect(BuildContext context, String id,
bool forceRelay = false,
String? password,
String? connToken,
bool? isSharedPassword}) async {
bool? isSharedPassword,
String loginMethod = ''}) async {
if (id == '') return;
if (!isDesktop || desktopType == DesktopType.main) {
try {
@@ -2603,6 +2634,7 @@ connect(BuildContext context, String id,
if (desktopType == DesktopType.main) {
await connectMainDesktop(
id,
loginMethod: loginMethod,
isFileTransfer: isFileTransfer,
isViewCamera: isViewCamera,
isTerminal: isTerminal,
@@ -2624,6 +2656,7 @@ connect(BuildContext context, String id,
'isSharedPassword': isSharedPassword,
'forceRelay': forceRelay,
'connToken': connToken,
'loginMethod': loginMethod,
});
}
} else {
@@ -2635,6 +2668,7 @@ connect(BuildContext context, String id,
builder: (BuildContext context) =>
desktop_file_manager.FileManagerPage(
id: id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword),
),
@@ -2645,6 +2679,7 @@ connect(BuildContext context, String id,
MaterialPageRoute(
builder: (BuildContext context) => FileManagerPage(
id: id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay),
@@ -2660,6 +2695,7 @@ connect(BuildContext context, String id,
desktop_view_camera.ViewCameraPage(
key: ValueKey(id),
id: id,
loginMethod: loginMethod,
toolbarState: ToolbarState(),
password: password,
isSharedPassword: isSharedPassword,
@@ -2672,6 +2708,7 @@ connect(BuildContext context, String id,
MaterialPageRoute(
builder: (BuildContext context) => ViewCameraPage(
id: id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay),
@@ -2684,6 +2721,7 @@ connect(BuildContext context, String id,
MaterialPageRoute(
builder: (BuildContext context) => TerminalPage(
id: id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay,
@@ -2698,6 +2736,7 @@ connect(BuildContext context, String id,
builder: (BuildContext context) => desktop_remote.RemotePage(
key: ValueKey(id),
id: id,
loginMethod: loginMethod,
toolbarState: ToolbarState(),
password: password,
isSharedPassword: isSharedPassword,
@@ -2710,6 +2749,7 @@ connect(BuildContext context, String id,
MaterialPageRoute(
builder: (BuildContext context) => RemotePage(
id: id,
loginMethod: loginMethod,
password: password,
isSharedPassword: isSharedPassword,
forceRelay: forceRelay),