diff --git a/src/App/Pages/Accounts/LockPage.xaml b/src/App/Pages/Accounts/LockPage.xaml
index 38b456ee7..53573cbc4 100644
--- a/src/App/Pages/Accounts/LockPage.xaml
+++ b/src/App/Pages/Accounts/LockPage.xaml
@@ -8,7 +8,7 @@
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:LockPageViewModel"
Title="{Binding PageTitle}">
-
+
@@ -87,6 +87,8 @@
+
diff --git a/src/App/Pages/Accounts/LockPage.xaml.cs b/src/App/Pages/Accounts/LockPage.xaml.cs
index 2623b3b18..bd1857882 100644
--- a/src/App/Pages/Accounts/LockPage.xaml.cs
+++ b/src/App/Pages/Accounts/LockPage.xaml.cs
@@ -59,5 +59,13 @@ namespace Bit.App.Pages
await _vm.LogOutAsync();
}
}
+
+ private async void Fingerprint_Clicked(object sender, EventArgs e)
+ {
+ if(DoOnce())
+ {
+ await _vm.PromptFingerprintAsync();
+ }
+ }
}
}
diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs
index aab615a86..ed0854b0f 100644
--- a/src/App/Pages/Accounts/LockPageViewModel.cs
+++ b/src/App/Pages/Accounts/LockPageViewModel.cs
@@ -21,10 +21,12 @@ namespace Bit.App.Pages
private readonly IUserService _userService;
private readonly IMessagingService _messagingService;
+ private bool _hasKey;
private string _email;
private bool _showPassword;
private bool _pinLock;
private bool _fingerprintLock;
+ private string _fingerprintButtonText;
private int _invalidPinAttempts = 0;
private Tuple _pinSet;
@@ -64,6 +66,12 @@ namespace Bit.App.Pages
set => SetProperty(ref _fingerprintLock, value);
}
+ public string FingerprintButtonText
+ {
+ get => _fingerprintButtonText;
+ set => SetProperty(ref _fingerprintButtonText, value);
+ }
+
public Command TogglePasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string MasterPassword { get; set; }
@@ -72,25 +80,19 @@ namespace Bit.App.Pages
public async Task InitAsync()
{
_pinSet = await _lockService.IsPinLockSetAsync();
- var hasKey = await _cryptoService.HasKeyAsync();
- PinLock = (_pinSet.Item1 && hasKey) || _pinSet.Item2;
+ _hasKey = await _cryptoService.HasKeyAsync();
+ PinLock = (_pinSet.Item1 && _hasKey) || _pinSet.Item2;
FingerprintLock = await _lockService.IsFingerprintLockSetAsync();
_email = await _userService.GetEmailAsync();
PageTitle = PinLock ? AppResources.VerifyPIN : AppResources.VerifyMasterPassword;
if(FingerprintLock)
{
+ FingerprintButtonText = AppResources.UseFingerprintToUnlock; // TODO: FaceID text
var tasks = Task.Run(async () =>
{
await Task.Delay(500);
- Device.BeginInvokeOnMainThread(async () => {
- var success = await _platformUtilsService.AuthenticateFingerprintAsync();
- _lockService.FingerprintLocked = !success;
- if(success)
- {
- DoContinue();
- }
- });
+ Device.BeginInvokeOnMainThread(async () => await PromptFingerprintAsync());
});
}
}
@@ -190,9 +192,34 @@ namespace Bit.App.Pages
entry.Focus();
}
+ public async Task PromptFingerprintAsync()
+ {
+ var success = await _platformUtilsService.AuthenticateFingerprintAsync(null,
+ PinLock ? AppResources.PIN : AppResources.MasterPassword, () =>
+ {
+ var page = Page as LockPage;
+ if(PinLock)
+ {
+ page.PinEntry.Focus();
+ }
+ else
+ {
+ page.MasterPasswordEntry.Focus();
+ }
+ });
+ _lockService.FingerprintLocked = !success;
+ if(success)
+ {
+ DoContinue();
+ }
+ }
+
private async Task SetKeyAndContinueAsync(SymmetricCryptoKey key)
{
- await _cryptoService.SetKeyAsync(key);
+ if(!_hasKey)
+ {
+ await _cryptoService.SetKeyAsync(key);
+ }
DoContinue();
}
diff --git a/src/App/Services/MobilePlatformUtilsService.cs b/src/App/Services/MobilePlatformUtilsService.cs
index 4e244df55..efbbec660 100644
--- a/src/App/Services/MobilePlatformUtilsService.cs
+++ b/src/App/Services/MobilePlatformUtilsService.cs
@@ -200,7 +200,8 @@ namespace Bit.App.Services
}
}
- public async Task AuthenticateFingerprintAsync(string text = null)
+ public async Task AuthenticateFingerprintAsync(string text = null, string fallbackText = null,
+ Action fallback = null)
{
try
{
@@ -212,13 +213,18 @@ namespace Bit.App.Services
var fingerprintRequest = new AuthenticationRequestConfiguration(text)
{
AllowAlternativeAuthentication = true,
- CancelTitle = AppResources.Cancel
+ CancelTitle = AppResources.Cancel,
+ FallbackTitle = fallbackText
};
var result = await CrossFingerprint.Current.AuthenticateAsync(fingerprintRequest);
if(result.Authenticated)
{
return true;
}
+ else if(result.Status == FingerprintAuthenticationResultStatus.FallbackRequested)
+ {
+ fallback?.Invoke();
+ }
}
catch { }
return false;
diff --git a/src/Core/Abstractions/IPlatformUtilsService.cs b/src/Core/Abstractions/IPlatformUtilsService.cs
index f7b545037..b0ac5354a 100644
--- a/src/Core/Abstractions/IPlatformUtilsService.cs
+++ b/src/Core/Abstractions/IPlatformUtilsService.cs
@@ -27,6 +27,6 @@ namespace Bit.Core.Abstractions
bool SupportsU2f();
bool SupportsDuo();
Task SupportsFingerprintAsync();
- Task AuthenticateFingerprintAsync(string text = null);
+ Task AuthenticateFingerprintAsync(string text = null, string fallbackText = null, Action fallback = null);
}
}
\ No newline at end of file