fingerprint locking

This commit is contained in:
Kyle Spearrin 2019-05-16 17:30:07 -04:00
parent 22a0b262e1
commit 5761b47073
11 changed files with 84 additions and 14 deletions

View file

@ -147,6 +147,7 @@ namespace Bit.App
_passwordGenerationService.ClearAsync(),
_lockService.ClearAsync());
_lockService.PinLocked = false;
_lockService.FingerprintLocked = true;
_searchService.ClearIndex();
_authService.LogOut(() =>
{

View file

@ -28,7 +28,7 @@ namespace Bit.App.Pages
{
RequestFocus(PinEntry);
}
else
else if(!_vm.FingerprintLock)
{
RequestFocus(MasterPasswordEntry);
}

View file

@ -24,6 +24,7 @@ namespace Bit.App.Pages
private string _email;
private bool _showPassword;
private bool _pinLock;
private bool _fingerprintLock;
private int _invalidPinAttempts = 0;
private Tuple<bool, bool> _pinSet;
@ -57,6 +58,12 @@ namespace Bit.App.Pages
set => SetProperty(ref _pinLock, value);
}
public bool FingerprintLock
{
get => _fingerprintLock;
set => SetProperty(ref _fingerprintLock, value);
}
public Command TogglePasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string MasterPassword { get; set; }
@ -67,8 +74,25 @@ namespace Bit.App.Pages
_pinSet = await _lockService.IsPinLockSetAsync();
var 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)
{
var tasks = Task.Run(async () =>
{
await Task.Delay(500);
Device.BeginInvokeOnMainThread(async () => {
var success = await _platformUtilsService.AuthenticateFingerprintAsync();
_lockService.FingerprintLocked = !success;
if(success)
{
DoContinue();
}
});
});
}
}
public async Task SubmitAsync()

View file

@ -102,6 +102,11 @@ namespace Bit.App.Pages
{
await _vm.UpdatePinAsync();
}
else if(item.Name.Contains(AppResources.Fingerprint) || item.Name.Contains(AppResources.TouchID) ||
item.Name.Contains(AppResources.FaceID))
{
await _vm.UpdateFingerprintAsync();
}
}
}
}

View file

@ -80,7 +80,7 @@ namespace Bit.App.Pages
_lockOptionValue = _lockOptions.FirstOrDefault(o => o.Value == option).Key;
var pinSet = await _lockService.IsPinLockSetAsync();
_pin = pinSet.Item1 || pinSet.Item2;
// TODO: Fingerprint
_fingerprint = await _lockService.IsFingerprintLockSetAsync();
BuildList();
}
@ -238,7 +238,21 @@ namespace Bit.App.Pages
await _storageService.RemoveAsync(Constants.PinProtectedKey);
await _storageService.RemoveAsync(Constants.ProtectedPin);
}
BuildList();
}
public async Task UpdateFingerprintAsync()
{
_fingerprint = !_fingerprint;
if(_fingerprint)
{
await _storageService.SaveAsync(Constants.FingerprintUnlockKey, true);
}
else
{
await _storageService.RemoveAsync(Constants.FingerprintUnlockKey);
}
await _cryptoService.ToggleKeyAsync();
BuildList();
}

View file

@ -200,29 +200,25 @@ namespace Bit.App.Services
}
}
public async Task<bool> AuthenticateFingerprintAsync(string text = null, Action fallback = null)
public async Task<bool> AuthenticateFingerprintAsync(string text = null)
{
try
{
if(text == null)
{
text = AppResources.FingerprintDirection;
// TODO: face id direction
}
var fingerprintRequest = new AuthenticationRequestConfiguration(text)
{
AllowAlternativeAuthentication = true,
CancelTitle = AppResources.Cancel,
FallbackTitle = AppResources.LogOut
CancelTitle = AppResources.Cancel
};
var result = await CrossFingerprint.Current.AuthenticateAsync(fingerprintRequest);
if(result.Authenticated)
{
return true;
}
else if(result.Status == FingerprintAuthenticationResultStatus.FallbackRequested)
{
fallback?.Invoke();
}
}
catch { }
return false;

View file

@ -6,11 +6,13 @@ namespace Bit.Core.Abstractions
public interface ILockService
{
bool PinLocked { get; set; }
bool FingerprintLocked { get; set; }
Task CheckLockAsync();
Task ClearAsync();
Task<bool> IsLockedAsync();
Task<Tuple<bool, bool>> IsPinLockSetAsync();
Task<bool> IsFingerprintLockSetAsync();
Task LockAsync(bool allowSoftLock = false);
Task SetLockOptionAsync(int? lockOption);
}

View file

@ -27,6 +27,6 @@ namespace Bit.Core.Abstractions
bool SupportsU2f();
bool SupportsDuo();
Task<bool> SupportsFingerprintAsync();
Task<bool> AuthenticateFingerprintAsync(string text = null, Action fallback = null);
Task<bool> AuthenticateFingerprintAsync(string text = null);
}
}

View file

@ -6,6 +6,7 @@
public const string iOSAppProtocol = "iosapp://";
public static string LockOptionKey = "lockOption";
public static string LastActiveKey = "lastActive";
public static string FingerprintUnlockKey = "fingerprintUnlock";
public static string ProtectedPin = "protectedPin";
public static string PinProtectedKey = "pinProtectedKey";
public static string DefaultUriMatch = "defaultUriMatch";

View file

@ -47,7 +47,8 @@ namespace Bit.Core.Services
{
_key = key;
var option = await _storageService.GetAsync<int?>(Constants.LockOptionKey);
if(option.HasValue)
var fingerprint = await _storageService.GetAsync<bool?>(Constants.FingerprintUnlockKey);
if(option.HasValue && !fingerprint.GetValueOrDefault())
{
// If we have a lock option set, we do not store the key
return;
@ -349,7 +350,8 @@ namespace Bit.Core.Services
{
var key = await GetKeyAsync();
var option = await _storageService.GetAsync<int?>(Constants.LockOptionKey);
if(option != null || option == 0)
var fingerprint = await _storageService.GetAsync<bool?>(Constants.FingerprintUnlockKey);
if(!fingerprint.GetValueOrDefault() && (option != null || option == 0))
{
await ClearKeyAsync();
_key = key;

View file

@ -39,15 +39,27 @@ namespace Bit.Core.Services
}
public bool PinLocked { get; set; }
public bool FingerprintLocked { get; set; } = true;
// TODO: init timer?
public async Task<bool> IsLockedAsync()
{
var hasKey = await _cryptoService.HasKeyAsync();
if(hasKey && PinLocked)
if(hasKey)
{
return true;
if(PinLocked)
{
return true;
}
else
{
var fingerprintSet = await IsFingerprintLockSetAsync();
if(fingerprintSet && FingerprintLocked)
{
return true;
}
}
}
return !hasKey;
}
@ -102,6 +114,13 @@ namespace Bit.Core.Services
if(pinSet.Item1)
{
PinLocked = true;
}
if(await IsFingerprintLockSetAsync())
{
FingerprintLocked = true;
}
if(FingerprintLocked || PinLocked)
{
_messagingService.Send("locked");
// TODO: locked callback?
return;
@ -134,6 +153,12 @@ namespace Bit.Core.Services
return new Tuple<bool, bool>(protectedPin != null, pinProtectedKey != null);
}
public async Task<bool> IsFingerprintLockSetAsync()
{
var fingerprintLock = await _storageService.GetAsync<bool?>(Constants.FingerprintUnlockKey);
return fingerprintLock.GetValueOrDefault();
}
public async Task ClearAsync()
{
await _storageService.RemoveAsync(Constants.ProtectedPin);