diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs index 3e6946c6a..7b9b0c7fc 100644 --- a/src/App/Pages/Accounts/LockPageViewModel.cs +++ b/src/App/Pages/Accounts/LockPageViewModel.cs @@ -465,7 +465,8 @@ namespace Bit.App.Pages } var success = await _platformUtilsService.AuthenticateBiometricAsync(null, PinEnabled ? AppResources.PIN : AppResources.MasterPassword, - () => _secretEntryFocusWeakEventManager.RaiseEvent((int?)null, nameof(FocusSecretEntry))); + () => _secretEntryFocusWeakEventManager.RaiseEvent((int?)null, nameof(FocusSecretEntry)), + !PinEnabled && !HasMasterPassword); await _stateService.SetBiometricLockedAsync(!success); if (success) { diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 023e47c93..9e1d83ef0 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -256,6 +256,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Account logged out.. + /// + public static string AccountLoggedOutBiometricExceeded { + get { + return ResourceManager.GetString("AccountLoggedOutBiometricExceeded", resourceCulture); + } + } + /// /// Looks up a localized string similar to Account logged out successfully. /// @@ -6498,6 +6507,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Too many attempts. + /// + public static string TooManyAttempts { + get { + return ResourceManager.GetString("TooManyAttempts", resourceCulture); + } + } + /// /// Looks up a localized string similar to TOTP. /// @@ -6751,7 +6769,7 @@ namespace Bit.App.Resources { } /// - /// Looks up a localized string similar to Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.. + /// Looks up a localized string similar to Unlocking may fail due to insufficient memory. Decrease your KDF memory settings or set up biometric unlock to resolve.. /// public static string UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve { get { diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index b983847b6..382794acd 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -2762,4 +2762,10 @@ Do you want to switch to this account? Logging in on + + Too many attempts + + + Account logged out. + diff --git a/src/App/Services/MobilePlatformUtilsService.cs b/src/App/Services/MobilePlatformUtilsService.cs index ea1a7e1dc..93d3201ad 100644 --- a/src/App/Services/MobilePlatformUtilsService.cs +++ b/src/App/Services/MobilePlatformUtilsService.cs @@ -32,7 +32,8 @@ namespace Bit.App.Services IDeviceActionService deviceActionService, IClipboardService clipboardService, IMessagingService messagingService, - IBroadcasterService broadcasterService) + IBroadcasterService broadcasterService + ) { _deviceActionService = deviceActionService; _clipboardService = clipboardService; @@ -242,7 +243,7 @@ namespace Bit.App.Services } public async Task AuthenticateBiometricAsync(string text = null, string fallbackText = null, - Action fallback = null) + Action fallback = null, bool logOutOnTooManyAttempts = false) { try { @@ -269,6 +270,12 @@ namespace Bit.App.Services { fallback?.Invoke(); } + if (result.Status == FingerprintAuthenticationResultStatus.TooManyAttempts + && logOutOnTooManyAttempts) + { + await ShowDialogAsync(AppResources.AccountLoggedOutBiometricExceeded, AppResources.TooManyAttempts, AppResources.Ok); + _messagingService.Send(AccountsManagerMessageCommands.LOGOUT); + } } catch { } return false; diff --git a/src/App/Utilities/AppHelpers.cs b/src/App/Utilities/AppHelpers.cs index 67e152b56..6ec36dcf8 100644 --- a/src/App/Utilities/AppHelpers.cs +++ b/src/App/Utilities/AppHelpers.cs @@ -15,6 +15,7 @@ using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Models.Data; using Bit.Core.Models.View; +using Bit.Core.Services; using Bit.Core.Utilities; using Newtonsoft.Json; using Xamarin.Essentials; diff --git a/src/Core/Abstractions/IPlatformUtilsService.cs b/src/Core/Abstractions/IPlatformUtilsService.cs index 2e8e8e7f6..3432238fa 100644 --- a/src/Core/Abstractions/IPlatformUtilsService.cs +++ b/src/Core/Abstractions/IPlatformUtilsService.cs @@ -29,7 +29,7 @@ namespace Bit.Core.Abstractions bool SupportsDuo(); Task SupportsBiometricAsync(); Task IsBiometricIntegrityValidAsync(string bioIntegritySrcKey = null); - Task AuthenticateBiometricAsync(string text = null, string fallbackText = null, Action fallback = null); + Task AuthenticateBiometricAsync(string text = null, string fallbackText = null, Action fallback = null, bool logOutOnTooManyAttempts = false); long GetActiveTime(); } } diff --git a/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs b/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs index 0befe3cf4..13ee37bea 100644 --- a/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs +++ b/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs @@ -378,7 +378,9 @@ namespace Bit.iOS.Core.Controllers } var success = await _platformUtilsService.AuthenticateBiometricAsync(null, _pinEnabled ? AppResources.PIN : AppResources.MasterPassword, - () => MasterPasswordCell.TextField.BecomeFirstResponder()); + () => MasterPasswordCell.TextField.BecomeFirstResponder(), + !_pinEnabled && !_hasMasterPassword); + await _stateService.SetBiometricLockedAsync(!success); if (success) {