mirror of
https://github.com/bitwarden/android.git
synced 2025-03-28 00:29:24 +03:00
fingerprint unlock
This commit is contained in:
parent
a7ad89471a
commit
4aa1209bc7
5 changed files with 58 additions and 15 deletions
|
@ -8,7 +8,7 @@
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||||
x:DataType="pages:LockPageViewModel"
|
x:DataType="pages:LockPageViewModel"
|
||||||
Title="{Binding PageTitle}">
|
Title="{Binding PageTitle}">
|
||||||
|
|
||||||
<ContentPage.BindingContext>
|
<ContentPage.BindingContext>
|
||||||
<pages:LockPageViewModel />
|
<pages:LockPageViewModel />
|
||||||
</ContentPage.BindingContext>
|
</ContentPage.BindingContext>
|
||||||
|
@ -87,6 +87,8 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout Padding="10, 0">
|
<StackLayout Padding="10, 0">
|
||||||
|
<Button Text="{Binding FingerprintButtonText}" Clicked="Fingerprint_Clicked"
|
||||||
|
IsVisible="{Binding FingerprintLock}"></Button>
|
||||||
<Button Text="{u:I18n LogOut}" Clicked="LogOut_Clicked"></Button>
|
<Button Text="{u:I18n LogOut}" Clicked="LogOut_Clicked"></Button>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
|
@ -59,5 +59,13 @@ namespace Bit.App.Pages
|
||||||
await _vm.LogOutAsync();
|
await _vm.LogOutAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void Fingerprint_Clicked(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if(DoOnce())
|
||||||
|
{
|
||||||
|
await _vm.PromptFingerprintAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,12 @@ namespace Bit.App.Pages
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
private readonly IMessagingService _messagingService;
|
private readonly IMessagingService _messagingService;
|
||||||
|
|
||||||
|
private bool _hasKey;
|
||||||
private string _email;
|
private string _email;
|
||||||
private bool _showPassword;
|
private bool _showPassword;
|
||||||
private bool _pinLock;
|
private bool _pinLock;
|
||||||
private bool _fingerprintLock;
|
private bool _fingerprintLock;
|
||||||
|
private string _fingerprintButtonText;
|
||||||
private int _invalidPinAttempts = 0;
|
private int _invalidPinAttempts = 0;
|
||||||
private Tuple<bool, bool> _pinSet;
|
private Tuple<bool, bool> _pinSet;
|
||||||
|
|
||||||
|
@ -64,6 +66,12 @@ namespace Bit.App.Pages
|
||||||
set => SetProperty(ref _fingerprintLock, value);
|
set => SetProperty(ref _fingerprintLock, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string FingerprintButtonText
|
||||||
|
{
|
||||||
|
get => _fingerprintButtonText;
|
||||||
|
set => SetProperty(ref _fingerprintButtonText, value);
|
||||||
|
}
|
||||||
|
|
||||||
public Command TogglePasswordCommand { get; }
|
public Command TogglePasswordCommand { get; }
|
||||||
public string ShowPasswordIcon => ShowPassword ? "" : "";
|
public string ShowPasswordIcon => ShowPassword ? "" : "";
|
||||||
public string MasterPassword { get; set; }
|
public string MasterPassword { get; set; }
|
||||||
|
@ -72,25 +80,19 @@ namespace Bit.App.Pages
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
_pinSet = await _lockService.IsPinLockSetAsync();
|
_pinSet = await _lockService.IsPinLockSetAsync();
|
||||||
var hasKey = await _cryptoService.HasKeyAsync();
|
_hasKey = await _cryptoService.HasKeyAsync();
|
||||||
PinLock = (_pinSet.Item1 && hasKey) || _pinSet.Item2;
|
PinLock = (_pinSet.Item1 && _hasKey) || _pinSet.Item2;
|
||||||
FingerprintLock = await _lockService.IsFingerprintLockSetAsync();
|
FingerprintLock = await _lockService.IsFingerprintLockSetAsync();
|
||||||
_email = await _userService.GetEmailAsync();
|
_email = await _userService.GetEmailAsync();
|
||||||
PageTitle = PinLock ? AppResources.VerifyPIN : AppResources.VerifyMasterPassword;
|
PageTitle = PinLock ? AppResources.VerifyPIN : AppResources.VerifyMasterPassword;
|
||||||
|
|
||||||
if(FingerprintLock)
|
if(FingerprintLock)
|
||||||
{
|
{
|
||||||
|
FingerprintButtonText = AppResources.UseFingerprintToUnlock; // TODO: FaceID text
|
||||||
var tasks = Task.Run(async () =>
|
var tasks = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
Device.BeginInvokeOnMainThread(async () => {
|
Device.BeginInvokeOnMainThread(async () => await PromptFingerprintAsync());
|
||||||
var success = await _platformUtilsService.AuthenticateFingerprintAsync();
|
|
||||||
_lockService.FingerprintLocked = !success;
|
|
||||||
if(success)
|
|
||||||
{
|
|
||||||
DoContinue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,9 +192,34 @@ namespace Bit.App.Pages
|
||||||
entry.Focus();
|
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)
|
private async Task SetKeyAndContinueAsync(SymmetricCryptoKey key)
|
||||||
{
|
{
|
||||||
await _cryptoService.SetKeyAsync(key);
|
if(!_hasKey)
|
||||||
|
{
|
||||||
|
await _cryptoService.SetKeyAsync(key);
|
||||||
|
}
|
||||||
DoContinue();
|
DoContinue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,8 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> AuthenticateFingerprintAsync(string text = null)
|
public async Task<bool> AuthenticateFingerprintAsync(string text = null, string fallbackText = null,
|
||||||
|
Action fallback = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -212,13 +213,18 @@ namespace Bit.App.Services
|
||||||
var fingerprintRequest = new AuthenticationRequestConfiguration(text)
|
var fingerprintRequest = new AuthenticationRequestConfiguration(text)
|
||||||
{
|
{
|
||||||
AllowAlternativeAuthentication = true,
|
AllowAlternativeAuthentication = true,
|
||||||
CancelTitle = AppResources.Cancel
|
CancelTitle = AppResources.Cancel,
|
||||||
|
FallbackTitle = fallbackText
|
||||||
};
|
};
|
||||||
var result = await CrossFingerprint.Current.AuthenticateAsync(fingerprintRequest);
|
var result = await CrossFingerprint.Current.AuthenticateAsync(fingerprintRequest);
|
||||||
if(result.Authenticated)
|
if(result.Authenticated)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if(result.Status == FingerprintAuthenticationResultStatus.FallbackRequested)
|
||||||
|
{
|
||||||
|
fallback?.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -27,6 +27,6 @@ namespace Bit.Core.Abstractions
|
||||||
bool SupportsU2f();
|
bool SupportsU2f();
|
||||||
bool SupportsDuo();
|
bool SupportsDuo();
|
||||||
Task<bool> SupportsFingerprintAsync();
|
Task<bool> SupportsFingerprintAsync();
|
||||||
Task<bool> AuthenticateFingerprintAsync(string text = null);
|
Task<bool> AuthenticateFingerprintAsync(string text = null, string fallbackText = null, Action fallback = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue