From 4aa1209bc7197e7746512d3711a4d8ea1404c0e0 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 17 May 2019 09:42:20 -0400 Subject: [PATCH] fingerprint unlock --- src/App/Pages/Accounts/LockPage.xaml | 4 +- src/App/Pages/Accounts/LockPage.xaml.cs | 8 +++ src/App/Pages/Accounts/LockPageViewModel.cs | 49 ++++++++++++++----- .../Services/MobilePlatformUtilsService.cs | 10 +++- .../Abstractions/IPlatformUtilsService.cs | 2 +- 5 files changed, 58 insertions(+), 15 deletions(-) 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