mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
unlock with PIN (#8977)
* add custom password to unlock settings * If not set, use admin password; if set, use custom settings password. * At least 4 characters. * Set with gui or command line. Signed-off-by: 21pages <sunboeasy@gmail.com> * Update cn.rs --------- Signed-off-by: 21pages <sunboeasy@gmail.com> Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
This commit is contained in:
@@ -679,6 +679,7 @@ class PasswordWidget extends StatefulWidget {
|
||||
this.reRequestFocus = false,
|
||||
this.hintText,
|
||||
this.errorText,
|
||||
this.title,
|
||||
}) : super(key: key);
|
||||
|
||||
final TextEditingController controller;
|
||||
@@ -686,6 +687,7 @@ class PasswordWidget extends StatefulWidget {
|
||||
final bool reRequestFocus;
|
||||
final String? hintText;
|
||||
final String? errorText;
|
||||
final String? title;
|
||||
|
||||
@override
|
||||
State<PasswordWidget> createState() => _PasswordWidgetState();
|
||||
@@ -729,7 +731,7 @@ class _PasswordWidgetState extends State<PasswordWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DialogTextField(
|
||||
title: translate(DialogTextField.kPasswordTitle),
|
||||
title: translate(widget.title ?? DialogTextField.kPasswordTitle),
|
||||
hintText: translate(widget.hintText ?? 'Enter your password'),
|
||||
controller: widget.controller,
|
||||
prefixIcon: DialogTextField.kPasswordIcon,
|
||||
@@ -2216,3 +2218,98 @@ void CommonConfirmDialog(OverlayDialogManager dialogManager, String content,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void changeUnlockPinDialog(String oldPin, Function() callback) {
|
||||
final pinController = TextEditingController(text: oldPin);
|
||||
final confirmController = TextEditingController(text: oldPin);
|
||||
String? pinErrorText;
|
||||
String? confirmationErrorText;
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() async {
|
||||
pinErrorText = null;
|
||||
confirmationErrorText = null;
|
||||
final pin = pinController.text.trim();
|
||||
final confirm = confirmController.text.trim();
|
||||
if (pin != confirm) {
|
||||
setState(() {
|
||||
confirmationErrorText =
|
||||
translate('The confirmation is not identical.');
|
||||
});
|
||||
return;
|
||||
}
|
||||
final errorMsg = bind.mainSetUnlockPin(pin: pin);
|
||||
if (errorMsg != '') {
|
||||
setState(() {
|
||||
pinErrorText = translate(errorMsg);
|
||||
});
|
||||
return;
|
||||
}
|
||||
callback.call();
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Set PIN")),
|
||||
content: Column(
|
||||
children: [
|
||||
DialogTextField(
|
||||
title: 'PIN',
|
||||
controller: pinController,
|
||||
obscureText: true,
|
||||
errorText: pinErrorText,
|
||||
),
|
||||
DialogTextField(
|
||||
title: translate('Confirmation'),
|
||||
controller: confirmController,
|
||||
obscureText: true,
|
||||
errorText: confirmationErrorText,
|
||||
)
|
||||
],
|
||||
).marginOnly(bottom: 12),
|
||||
actions: [
|
||||
dialogButton(translate("Cancel"), onPressed: close, isOutline: true),
|
||||
dialogButton(translate("OK"), onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void checkUnlockPinDialog(String correctPin, Function() passCallback) {
|
||||
final controller = TextEditingController();
|
||||
String? errorText;
|
||||
gFFI.dialogManager.show((setState, close, context) {
|
||||
submit() async {
|
||||
final pin = controller.text.trim();
|
||||
if (correctPin != pin) {
|
||||
setState(() {
|
||||
errorText = translate('Wrong PIN');
|
||||
});
|
||||
return;
|
||||
}
|
||||
passCallback.call();
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
content: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: PasswordWidget(
|
||||
title: 'PIN',
|
||||
controller: controller,
|
||||
errorText: errorText,
|
||||
hintText: '',
|
||||
))
|
||||
],
|
||||
).marginOnly(bottom: 12),
|
||||
actions: [
|
||||
dialogButton(translate("Cancel"), onPressed: close, isOutline: true),
|
||||
dialogButton(translate("OK"), onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1018,6 +1018,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
||||
_OptionCheckBox(context, 'allow-only-conn-window-open-tip',
|
||||
'allow-only-conn-window-open',
|
||||
reverse: false, enabled: enabled),
|
||||
if (bind.mainIsInstalled()) unlockPin()
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1265,6 +1266,40 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
|
||||
}(),
|
||||
];
|
||||
}
|
||||
|
||||
Widget unlockPin() {
|
||||
bool enabled = !locked;
|
||||
RxString unlockPin = bind.mainGetUnlockPin().obs;
|
||||
update() async {
|
||||
unlockPin.value = bind.mainGetUnlockPin();
|
||||
}
|
||||
|
||||
onChanged(bool? checked) async {
|
||||
changeUnlockPinDialog(unlockPin.value, update);
|
||||
}
|
||||
|
||||
final isOptFixed = isOptionFixed(kOptionWhitelist);
|
||||
return GestureDetector(
|
||||
child: Obx(() => Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: unlockPin.isNotEmpty,
|
||||
onChanged: enabled && !isOptFixed ? onChanged : null)
|
||||
.marginOnly(right: 5),
|
||||
Expanded(
|
||||
child: Text(
|
||||
translate('Unlock with PIN'),
|
||||
style: TextStyle(color: disabledTextColor(context, enabled)),
|
||||
))
|
||||
],
|
||||
)),
|
||||
onTap: enabled
|
||||
? () {
|
||||
onChanged(!unlockPin.isNotEmpty);
|
||||
}
|
||||
: null,
|
||||
).marginOnly(left: _kCheckBoxLeftMargin);
|
||||
}
|
||||
}
|
||||
|
||||
class _Network extends StatefulWidget {
|
||||
@@ -2160,9 +2195,14 @@ Widget _lock(
|
||||
Text(translate(label)).marginOnly(left: 5),
|
||||
]).marginSymmetric(vertical: 2)),
|
||||
onPressed: () async {
|
||||
bool checked = await callMainCheckSuperUserPermission();
|
||||
if (checked) {
|
||||
onUnlock();
|
||||
final unlockPin = bind.mainGetUnlockPin();
|
||||
if (unlockPin.isEmpty) {
|
||||
bool checked = await callMainCheckSuperUserPermission();
|
||||
if (checked) {
|
||||
onUnlock();
|
||||
}
|
||||
} else {
|
||||
checkUnlockPinDialog(unlockPin, onUnlock);
|
||||
}
|
||||
},
|
||||
).marginSymmetric(horizontal: 2, vertical: 4),
|
||||
|
||||
@@ -1622,5 +1622,13 @@ class RustdeskImpl {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
String mainGetUnlockPin({dynamic hint}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
String mainSetUnlockPin({required String pin, dynamic hint}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
void dispose() {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user