From 52024109f7bfd6ae36c6273d03076242c99fd63f Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Thu, 20 Jan 2022 09:51:42 -0500 Subject: [PATCH] Check for disable save prompt option before sending fill request in Android Autofill (#1722) * Check for disable save prompt option before sending fill request - ignore save request payload if true * Add exception handling to Autofill Service * move System reference outside of FDROID --- src/Android/Autofill/AutofillHelpers.cs | 5 +- src/Android/Autofill/AutofillService.cs | 223 +++++++++++++----------- 2 files changed, 127 insertions(+), 101 deletions(-) diff --git a/src/Android/Autofill/AutofillHelpers.cs b/src/Android/Autofill/AutofillHelpers.cs index d3ceae8d7..ab10aa005 100644 --- a/src/Android/Autofill/AutofillHelpers.cs +++ b/src/Android/Autofill/AutofillHelpers.cs @@ -160,7 +160,7 @@ namespace Bit.Droid.Autofill return new List(); } - public static FillResponse BuildFillResponse(Parser parser, List items, bool locked, + public static FillResponse.Builder CreateFillResponse(Parser parser, List items, bool locked, bool inlineAutofillEnabled, FillRequest fillRequest = null) { // Acquire inline presentation specs on Android 11+ @@ -211,9 +211,8 @@ namespace Bit.Droid.Autofill } responseBuilder.AddDataset(BuildVaultDataset(parser.ApplicationContext, parser.FieldCollection, parser.Uri, locked, inlinePresentationSpecs)); - AddSaveInfo(parser, fillRequest, responseBuilder, parser.FieldCollection); responseBuilder.SetIgnoredIds(parser.FieldCollection.IgnoreAutofillIds.ToArray()); - return responseBuilder.Build(); + return responseBuilder; } public static Dataset BuildDataset(Context context, FieldCollection fields, FilledItem filledItem, diff --git a/src/Android/Autofill/AutofillService.cs b/src/Android/Autofill/AutofillService.cs index 38ecbe4a9..0d0b1cc07 100644 --- a/src/Android/Autofill/AutofillService.cs +++ b/src/Android/Autofill/AutofillService.cs @@ -9,6 +9,10 @@ using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; using Bit.Core.Utilities; +#if !FDROID +using Microsoft.AppCenter.Crashes; +#endif +using System; using System.Collections.Generic; using System.Linq; @@ -29,115 +33,138 @@ namespace Bit.Droid.Autofill public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) { - var structure = request.FillContexts?.LastOrDefault()?.Structure; - if (structure == null) + try { - return; - } - - var parser = new Parser(structure, ApplicationContext); - parser.Parse(); - - if (_storageService == null) - { - _storageService = ServiceContainer.Resolve("storageService"); - } - - var shouldAutofill = await parser.ShouldAutofillAsync(_storageService); - if (!shouldAutofill) - { - return; - } - - var inlineAutofillEnabled = await _storageService.GetAsync(Constants.InlineAutofillEnabledKey) ?? true; - - if (_vaultTimeoutService == null) - { - _vaultTimeoutService = ServiceContainer.Resolve("vaultTimeoutService"); - } - - List items = null; - await _vaultTimeoutService.CheckVaultTimeoutAsync(); - var locked = await _vaultTimeoutService.IsLockedAsync(); - if (!locked) - { - if (_cipherService == null) + var structure = request.FillContexts?.LastOrDefault()?.Structure; + if (structure == null) { - _cipherService = ServiceContainer.Resolve("cipherService"); + return; } - items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService); - } - // build response - var response = AutofillHelpers.BuildFillResponse(parser, items, locked, inlineAutofillEnabled, request); - callback.OnSuccess(response); + var parser = new Parser(structure, ApplicationContext); + parser.Parse(); + + if (_storageService == null) + { + _storageService = ServiceContainer.Resolve("storageService"); + } + + var shouldAutofill = await parser.ShouldAutofillAsync(_storageService); + if (!shouldAutofill) + { + return; + } + + var inlineAutofillEnabled = await _storageService.GetAsync(Constants.InlineAutofillEnabledKey) ?? true; + + if (_vaultTimeoutService == null) + { + _vaultTimeoutService = ServiceContainer.Resolve("vaultTimeoutService"); + } + + List items = null; + await _vaultTimeoutService.CheckVaultTimeoutAsync(); + var locked = await _vaultTimeoutService.IsLockedAsync(); + if (!locked) + { + if (_cipherService == null) + { + _cipherService = ServiceContainer.Resolve("cipherService"); + } + items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService); + } + + // build response + var response = AutofillHelpers.CreateFillResponse(parser, items, locked, inlineAutofillEnabled, request); + var disableSavePrompt = await _storageService.GetAsync(Constants.AutofillDisableSavePromptKey); + if (!disableSavePrompt.GetValueOrDefault()) + { + AutofillHelpers.AddSaveInfo(parser, request, response, parser.FieldCollection); + } + callback.OnSuccess(response.Build()); + } + catch (Exception e) + { +#if !FDROID + Crashes.TrackError(e); +#endif + } } public async override void OnSaveRequest(SaveRequest request, SaveCallback callback) { - var structure = request.FillContexts?.LastOrDefault()?.Structure; - if (structure == null) + try { - return; - } - - if (_storageService == null) - { - _storageService = ServiceContainer.Resolve("storageService"); - } - - var disableSavePrompt = await _storageService.GetAsync(Constants.AutofillDisableSavePromptKey); - if (disableSavePrompt.GetValueOrDefault()) - { - return; - } - - _policyService ??= ServiceContainer.Resolve("policyService"); - - var personalOwnershipPolicyApplies = await _policyService.PolicyAppliesToUser(PolicyType.PersonalOwnership); - if (personalOwnershipPolicyApplies) - { - return; - } - - var parser = new Parser(structure, ApplicationContext); - parser.Parse(); - - var savedItem = parser.FieldCollection.GetSavedItem(); - if (savedItem == null) - { - Toast.MakeText(this, "Unable to save this form.", ToastLength.Short).Show(); - return; - } - - var intent = new Intent(this, typeof(MainActivity)); - intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop); - intent.PutExtra("autofillFramework", true); - intent.PutExtra("autofillFrameworkSave", true); - intent.PutExtra("autofillFrameworkType", (int)savedItem.Type); - switch (savedItem.Type) - { - case CipherType.Login: - intent.PutExtra("autofillFrameworkName", parser.Uri - .Replace(Constants.AndroidAppProtocol, string.Empty) - .Replace("https://", string.Empty) - .Replace("http://", string.Empty)); - intent.PutExtra("autofillFrameworkUri", parser.Uri); - intent.PutExtra("autofillFrameworkUsername", savedItem.Login.Username); - intent.PutExtra("autofillFrameworkPassword", savedItem.Login.Password); - break; - case CipherType.Card: - intent.PutExtra("autofillFrameworkCardName", savedItem.Card.Name); - intent.PutExtra("autofillFrameworkCardNumber", savedItem.Card.Number); - intent.PutExtra("autofillFrameworkCardExpMonth", savedItem.Card.ExpMonth); - intent.PutExtra("autofillFrameworkCardExpYear", savedItem.Card.ExpYear); - intent.PutExtra("autofillFrameworkCardCode", savedItem.Card.Code); - break; - default: - Toast.MakeText(this, "Unable to save this type of form.", ToastLength.Short).Show(); + var structure = request.FillContexts?.LastOrDefault()?.Structure; + if (structure == null) + { return; + } + + if (_storageService == null) + { + _storageService = ServiceContainer.Resolve("storageService"); + } + + var disableSavePrompt = await _storageService.GetAsync(Constants.AutofillDisableSavePromptKey); + if (disableSavePrompt.GetValueOrDefault()) + { + return; + } + + _policyService ??= ServiceContainer.Resolve("policyService"); + + var personalOwnershipPolicyApplies = await _policyService.PolicyAppliesToUser(PolicyType.PersonalOwnership); + if (personalOwnershipPolicyApplies) + { + return; + } + + var parser = new Parser(structure, ApplicationContext); + parser.Parse(); + + var savedItem = parser.FieldCollection.GetSavedItem(); + if (savedItem == null) + { + Toast.MakeText(this, "Unable to save this form.", ToastLength.Short).Show(); + return; + } + + var intent = new Intent(this, typeof(MainActivity)); + intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop); + intent.PutExtra("autofillFramework", true); + intent.PutExtra("autofillFrameworkSave", true); + intent.PutExtra("autofillFrameworkType", (int)savedItem.Type); + switch (savedItem.Type) + { + case CipherType.Login: + intent.PutExtra("autofillFrameworkName", parser.Uri + .Replace(Constants.AndroidAppProtocol, string.Empty) + .Replace("https://", string.Empty) + .Replace("http://", string.Empty)); + intent.PutExtra("autofillFrameworkUri", parser.Uri); + intent.PutExtra("autofillFrameworkUsername", savedItem.Login.Username); + intent.PutExtra("autofillFrameworkPassword", savedItem.Login.Password); + break; + case CipherType.Card: + intent.PutExtra("autofillFrameworkCardName", savedItem.Card.Name); + intent.PutExtra("autofillFrameworkCardNumber", savedItem.Card.Number); + intent.PutExtra("autofillFrameworkCardExpMonth", savedItem.Card.ExpMonth); + intent.PutExtra("autofillFrameworkCardExpYear", savedItem.Card.ExpYear); + intent.PutExtra("autofillFrameworkCardCode", savedItem.Card.Code); + break; + default: + Toast.MakeText(this, "Unable to save this type of form.", ToastLength.Short).Show(); + return; + } + StartActivity(intent); + } + catch (Exception e) + { +#if !FDROID + Crashes.TrackError(e); +#endif } - StartActivity(intent); } } }