From 6d5419964b8bca50b659f58996003de934df0499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Chiotti?= <44336112+maelchiotti@users.noreply.github.com> Date: Fri, 29 May 2026 23:55:02 +0200 Subject: [PATCH] fix: ask for authentication when required (toggling lock state, deleting locked label, toggling lock preference...) --- lib/common/actions/authentication.dart | 53 ++++++++++++++++++ lib/common/actions/labels/delete.dart | 28 ++++++++++ lib/common/actions/labels/lock.dart | 15 ++--- lib/common/actions/notes/lock.dart | 28 +++------- .../swipe_actions/available_swipe_action.dart | 2 +- lib/models/label/label.dart | 11 +++- lib/models/note/note.dart | 12 ++++ lib/pages/editor/editor_page.dart | 8 +-- lib/pages/lock/lock_page.dart | 44 +-------------- .../pages/settings_security_page.dart | 56 ++++++++++++++++--- 10 files changed, 169 insertions(+), 88 deletions(-) create mode 100644 lib/common/actions/authentication.dart diff --git a/lib/common/actions/authentication.dart b/lib/common/actions/authentication.dart new file mode 100644 index 00000000..2cde58c0 --- /dev/null +++ b/lib/common/actions/authentication.dart @@ -0,0 +1,53 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:restart_app/restart_app.dart'; + +import '../constants/constants.dart'; +import '../extensions/build_context_extension.dart'; +import '../preferences/preference_key.dart'; +import '../ui/snack_bar_utils.dart'; + +/// Asks the user to authenticate for the specified [reason] using the device lock method. +Future authenticate(BuildContext context, {required String reason}) async { + final localAuthentication = LocalAuthentication(); + + final canAuthenticate = await localAuthentication.isDeviceSupported(); + + // If the device has no authentication methods available, + // disable the app lock and restart it to remove the lock screen + if (!canAuthenticate) { + await PreferenceKey.lockApp.set(false); + + // The Restart package crashes the app if used in debug mode + if (kReleaseMode) { + await Restart.restartApp(); + } + + return false; + } + + bool authenticated; + try { + authenticated = await localAuthentication.authenticate(localizedReason: reason); + } on LocalAuthException catch (exception) { + if (exception.code != LocalAuthExceptionCode.userCanceled) { + logger.w("Authentication failed", exception); + } + + authenticated = false; + } + + // The authentication failed + if (!authenticated) { + if (!context.mounted) { + return false; + } + + SnackBarUtils().show(context, text: context.l.snack_bar_authentication_failed); + + return false; + } + + return true; +} diff --git a/lib/common/actions/labels/delete.dart b/lib/common/actions/labels/delete.dart index 6473bb59..ff65db37 100644 --- a/lib/common/actions/labels/delete.dart +++ b/lib/common/actions/labels/delete.dart @@ -5,6 +5,7 @@ import '../../../models/label/label.dart'; import '../../../providers/labels/labels/labels_provider.dart'; import '../../dialogs/confirmation_dialog.dart'; import '../../extensions/build_context_extension.dart'; +import '../authentication.dart'; import 'select.dart'; /// Deletes the [label]. @@ -23,6 +24,19 @@ Future deleteLabel(BuildContext context, WidgetRef ref, {required Label la return false; } + if (!context.mounted) { + return false; + } + + // If required, ask for authentication + if (label.requiresAuthentication) { + final authenticated = await authenticate(context, reason: context.l.lock_page_reason_action); + + if (!authenticated) { + return false; + } + } + return await ref.read(labelsProvider.notifier).delete([label]); } @@ -42,6 +56,20 @@ Future deleteLabels(BuildContext context, WidgetRef ref, {required List label.requiresAuthentication); + if (requiresAuthentication) { + final authenticated = await authenticate(context, reason: context.l.lock_page_reason_action); + + if (!authenticated) { + return false; + } + } + final succeeded = await ref.read(labelsProvider.notifier).delete(labels); if (context.mounted) { diff --git a/lib/common/actions/labels/lock.dart b/lib/common/actions/labels/lock.dart index 2d6705c7..fc4dfea1 100644 --- a/lib/common/actions/labels/lock.dart +++ b/lib/common/actions/labels/lock.dart @@ -1,23 +1,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:local_auth/local_auth.dart'; import '../../../models/label/label.dart'; import '../../../providers/labels/labels/labels_provider.dart'; import '../../extensions/build_context_extension.dart'; -import '../../preferences/preference_key.dart'; +import '../authentication.dart'; import 'select.dart'; /// Toggles whether the [labels] are locked. Future toggleLockLabels(BuildContext context, WidgetRef ref, {required List