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)
{