From c79bdf758994870f3ff1b06fc231ba111ab90213 Mon Sep 17 00:00:00 2001 From: luckyrat Date: Wed, 20 Mar 2024 15:44:49 +0000 Subject: [PATCH] Fix bug where duplicate entries could be saved from Android AutoFill Could only reproduce on Android 14 but am unsure what could explain that so probably also affected older Android versions sometimes too. --- lib/cubit/autofill_cubit.dart | 1 + lib/cubit/entry_cubit.dart | 2 ++ lib/cubit/vault_cubit.dart | 3 +++ lib/widgets/autofill_save.dart | 6 ++++++ lib/widgets/kee_vault_app.dart | 2 +- lib/widgets/vault.dart | 6 +++++- 6 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/cubit/autofill_cubit.dart b/lib/cubit/autofill_cubit.dart index 86959a4..f44a2e1 100644 --- a/lib/cubit/autofill_cubit.dart +++ b/lib/cubit/autofill_cubit.dart @@ -66,6 +66,7 @@ class AutofillCubit extends Cubit { } Future finishSaving() async { + l.t('Autofillcubit.finishSaving'); if (state is AutofillSaving || state is AutofillSaved) { emit(AutofillSaved((state as AutofillModeActive).androidMetadata)); await AutofillService().onSaveComplete(); diff --git a/lib/cubit/entry_cubit.dart b/lib/cubit/entry_cubit.dart index e2cf057..e56fbef 100644 --- a/lib/cubit/entry_cubit.dart +++ b/lib/cubit/entry_cubit.dart @@ -15,11 +15,13 @@ class EntryCubit extends Cubit { EntryCubit() : super(EntryInitial()); void startEditing(KdbxEntry entry, {bool startDirty = false}) { + l.t('EntryCubit.startEditing'); final newEntry = EditEntryViewModel.fromKdbxEntry(entry).let((it) => startDirty ? it.copyWith(isDirty: true) : it); emit(EntryLoaded(newEntry)); } void endEditing(KdbxEntry? entry) { + l.t('EntryCubit.endEditing'); if (entry != null) { (state as EntryLoaded).entry.commit(entry); } diff --git a/lib/cubit/vault_cubit.dart b/lib/cubit/vault_cubit.dart index 60f4460..4a5752c 100644 --- a/lib/cubit/vault_cubit.dart +++ b/lib/cubit/vault_cubit.dart @@ -279,6 +279,8 @@ class VaultCubit extends Cubit { final rootGroup = vault.files.current.body.rootGroup; initAutofillPersistentQueue(rootGroup.uuid.uuidUrlSafe); if (isAutofilling()) { + // Make sure that any previous autofill operations have their adjustments + // applied before we present the entry list or entry saving interface to the user. await _persistentQueueAfAssociations?.ready; final pendingItems = (await _persistentQueueAfAssociations?.toList()); if (pendingItems != null) { @@ -1272,6 +1274,7 @@ class VaultCubit extends Cubit { KdbxEntry createEntry({ required KdbxGroup group, }) { + l.t('VaultCubit.createEntry'); final destinationGroup = group; final entry = KdbxEntry.create(currentVaultFile!.files.current, destinationGroup); destinationGroup.addEntry(entry); diff --git a/lib/widgets/autofill_save.dart b/lib/widgets/autofill_save.dart index ebfadcf..454776e 100644 --- a/lib/widgets/autofill_save.dart +++ b/lib/widgets/autofill_save.dart @@ -9,6 +9,7 @@ import 'package:keevault/cubit/vault_cubit.dart'; import 'package:keevault/extension_methods.dart'; import 'package:keevault/widgets/loading_spinner.dart'; import 'package:matomo_tracker/matomo_tracker.dart'; +import '../logging/logger.dart'; import 'coloured_safe_area_widget.dart'; import 'entry.dart'; @@ -28,6 +29,7 @@ class _AutofillSaveWidgetState extends State with TraceableC KdbxEntry? newEntry; @override void initState() { + l.t('_AutofillSaveWidgetState.initState'); super.initState(); final autofillState = BlocProvider.of(context).state as AutofillModeActive; final vaultCubit = BlocProvider.of(context); @@ -39,6 +41,10 @@ class _AutofillSaveWidgetState extends State with TraceableC final password = autofillState.androidMetadata.saveInfo!.password; //TODO:f: expose value of save compat mode to Entry widget: //final isCompatMode = autofillState.androidMetadata.saveInfo!.isCompatMode; + + // We'll get duplicate entries if multiple instances of this widget are built. + // Should move the business logic to somewhere else if possible and have this + // widget just show whatever new entry has been supplied to it (e.g. by the cubit). setState(() { newEntry = vaultCubit.createEntry(group: vault.files.current.body.rootGroup); }); diff --git a/lib/widgets/kee_vault_app.dart b/lib/widgets/kee_vault_app.dart index 43887c9..fd50717 100644 --- a/lib/widgets/kee_vault_app.dart +++ b/lib/widgets/kee_vault_app.dart @@ -235,7 +235,7 @@ class KeeVaultAppState extends State with WidgetsBindingObserver, T RemoteVaultRepository(userService, storageService), LocalVaultRepository(quickUnlocker), entryCubit, - autofillCubit.isAutofilling, + () => autofillCubit.isAutofilling() || autofillCubit.isAutofillSaving(), generatorProfilesCubit, accountCubit, )), diff --git a/lib/widgets/vault.dart b/lib/widgets/vault.dart index 0d330a1..dec57b0 100644 --- a/lib/widgets/vault.dart +++ b/lib/widgets/vault.dart @@ -40,8 +40,12 @@ class _VaultWidgetState extends State with WidgetsBindingObserver { Future _refresh() async { final user = BlocProvider.of(context).currentUserIfKnown; + if (user == null) { + return; + } final AutofillState autofillState = BlocProvider.of(context).state; - if (autofillState is AutofillModeActive || user == null) { + if (autofillState is AutofillModeActive) { + l.t('Skip refresh due to state: ${autofillState.runtimeType}'); return; } await BlocProvider.of(context).refresh(user);