mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
2fa for unattended access
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:flutter_hbb/common/shared_state.dart';
|
||||
import 'package:flutter_hbb/common/widgets/setting_widgets.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../models/model.dart';
|
||||
@@ -1501,3 +1502,124 @@ void renameDialog(
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void change2fa({Function()? callback}) async {
|
||||
if (bind.mainHasValid2FaSync()) {
|
||||
await bind.mainSetOption(key: "2fa", value: "");
|
||||
callback?.call();
|
||||
return;
|
||||
}
|
||||
var new2fa = (await bind.mainGenerate2Fa());
|
||||
final secretRegex = RegExp(r'secret=([^&]+)');
|
||||
final secret = secretRegex.firstMatch(new2fa)?.group(1);
|
||||
var msg = ''.obs;
|
||||
final RxString code = "".obs;
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("enable-2fa-title")),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SelectableText(translate("enable-2fa-desc"),
|
||||
style: TextStyle(fontSize: 12))
|
||||
.marginOnly(bottom: 12),
|
||||
SizedBox(
|
||||
width: 160,
|
||||
height: 160,
|
||||
child: QrImageView(
|
||||
backgroundColor: Colors.white,
|
||||
data: new2fa,
|
||||
version: QrVersions.auto,
|
||||
size: 160,
|
||||
gapless: false,
|
||||
)).marginOnly(bottom: 6),
|
||||
SelectableText(secret ?? '', style: TextStyle(fontSize: 12))
|
||||
.marginOnly(bottom: 12),
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: Obx(() => TextField(
|
||||
decoration: InputDecoration(
|
||||
errorText:
|
||||
msg.value.isEmpty ? null : translate(msg.value),
|
||||
hintText: translate("Verification code")),
|
||||
onChanged: (value) {
|
||||
code.value = value;
|
||||
msg.value = '';
|
||||
},
|
||||
autofocus: true)))
|
||||
]),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
dialogButton("Cancel", onPressed: close, isOutline: true),
|
||||
Obx(() => dialogButton(
|
||||
"OK",
|
||||
onPressed: code.value.trim().length == 6
|
||||
? () async {
|
||||
if (await bind.mainVerify2Fa(code: code.value.trim())) {
|
||||
callback?.call();
|
||||
close();
|
||||
} else {
|
||||
msg.value = translate('wrong-2fa-code');
|
||||
}
|
||||
}
|
||||
: null,
|
||||
)),
|
||||
],
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void enter2FaDialog(
|
||||
SessionID sessionId, OverlayDialogManager dialogManager) async {
|
||||
final RxString code = "".obs;
|
||||
dialogManager.dismissAll();
|
||||
dialogManager.show((setState, close, context) {
|
||||
cancel() {
|
||||
close();
|
||||
closeConnection();
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (code.value.trim().length != 6) {
|
||||
return;
|
||||
}
|
||||
gFFI.send2FA(sessionId, code.value.trim());
|
||||
close();
|
||||
dialogManager.showLoading(translate('Logging in...'),
|
||||
onCancel: closeConnection);
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("enter-2fa-title")),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
hintText: translate("Verification code")),
|
||||
onChanged: (value) {
|
||||
code.value = value;
|
||||
},
|
||||
autofocus: true))
|
||||
]),
|
||||
],
|
||||
),
|
||||
onSubmit: submit,
|
||||
onCancel: cancel,
|
||||
actions: [
|
||||
dialogButton(
|
||||
'Cancel',
|
||||
onPressed: cancel,
|
||||
isOutline: true,
|
||||
),
|
||||
Obx(() => dialogButton(
|
||||
'OK',
|
||||
onPressed: code.value.trim().length == 6 ? submit : null,
|
||||
)),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import 'package:flutter_hbb/common/widgets/setting_widgets.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||
import 'package:flutter_hbb/models/desktop_render_texture.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/server_model.dart';
|
||||
import 'package:flutter_hbb/plugin/manager.dart';
|
||||
@@ -567,6 +566,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
||||
child: Column(children: [
|
||||
permissions(context),
|
||||
password(context),
|
||||
_Card(title: '2FA', children: [tfa()]),
|
||||
_Card(title: 'ID', children: [changeId()]),
|
||||
more(context),
|
||||
]),
|
||||
@@ -575,6 +575,45 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
||||
)).marginOnly(bottom: _kListViewBottomMargin));
|
||||
}
|
||||
|
||||
Widget tfa() {
|
||||
bool enabled = !locked;
|
||||
// Simple temp wrapper for PR check
|
||||
tmpWrapper() {
|
||||
RxBool has2fa = bind.mainHasValid2FaSync().obs;
|
||||
update() async {
|
||||
has2fa.value = bind.mainHasValid2FaSync();
|
||||
}
|
||||
|
||||
onChanged(bool? checked) async {
|
||||
change2fa(callback: update);
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
child: InkWell(
|
||||
child: Obx(() => Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: has2fa.value,
|
||||
onChanged: enabled ? onChanged : null)
|
||||
.marginOnly(right: 5),
|
||||
Expanded(
|
||||
child: Text(
|
||||
translate('enable-2fa-title'),
|
||||
style:
|
||||
TextStyle(color: _disabledTextColor(context, enabled)),
|
||||
))
|
||||
],
|
||||
)),
|
||||
),
|
||||
onTap: () {
|
||||
onChanged(!has2fa.value);
|
||||
},
|
||||
).marginOnly(left: _kCheckBoxLeftMargin);
|
||||
}
|
||||
|
||||
return tmpWrapper();
|
||||
}
|
||||
|
||||
Widget changeId() {
|
||||
return ChangeNotifierProvider.value(
|
||||
value: gFFI.serverModel,
|
||||
|
||||
@@ -220,6 +220,16 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
||||
Provider.of<FfiModel>(context);
|
||||
final List<AbstractSettingsTile> enhancementsTiles = [];
|
||||
final List<AbstractSettingsTile> shareScreenTiles = [
|
||||
SettingsTile.switchTile(
|
||||
title: Text(translate('enable-2fa-title')),
|
||||
initialValue: bind.mainHasValid2FaSync(),
|
||||
onToggle: (_) async {
|
||||
update() async {
|
||||
setState(() {});
|
||||
}
|
||||
change2fa(callback: update);
|
||||
},
|
||||
),
|
||||
SettingsTile.switchTile(
|
||||
title: Text(translate('Deny LAN discovery')),
|
||||
initialValue: _denyLANDiscovery,
|
||||
|
||||
@@ -498,6 +498,8 @@ class FfiModel with ChangeNotifier {
|
||||
final link = evt['link'];
|
||||
if (type == 're-input-password') {
|
||||
wrongPasswordDialog(sessionId, dialogManager, type, title, text);
|
||||
} else if (type == 'input-2fa') {
|
||||
enter2FaDialog(sessionId, dialogManager);
|
||||
} else if (type == 'input-password') {
|
||||
enterPasswordDialog(sessionId, dialogManager);
|
||||
} else if (type == 'session-login' || type == 'session-re-login') {
|
||||
@@ -2303,6 +2305,10 @@ class FFI {
|
||||
remember: remember);
|
||||
}
|
||||
|
||||
void send2FA(SessionID sessionId, String code) {
|
||||
bind.sessionSend2Fa(sessionId: sessionId, code: code);
|
||||
}
|
||||
|
||||
/// Close the remote session.
|
||||
Future<void> close({bool closeSession = true}) async {
|
||||
closed = true;
|
||||
|
||||
Reference in New Issue
Block a user