mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
biometric integrity check in iOS extensions (#1093)
This commit is contained in:
parent
0387d5bdd1
commit
7b358b1bbb
4 changed files with 59 additions and 16 deletions
|
@ -111,7 +111,7 @@
|
||||||
StyleClass="box-footer-label,text-danger,text-bold"
|
StyleClass="box-footer-label,text-danger,text-bold"
|
||||||
IsVisible="{Binding BiometricIntegrityValid, Converter={StaticResource inverseBool}}" />
|
IsVisible="{Binding BiometricIntegrityValid, Converter={StaticResource inverseBool}}" />
|
||||||
<Button Text="{Binding BiometricButtonText}" Clicked="Biometric_Clicked"
|
<Button Text="{Binding BiometricButtonText}" Clicked="Biometric_Clicked"
|
||||||
IsVisible="{Binding BiometricLock}" IsEnabled="{Binding BiometricIntegrityValid}"></Button>
|
IsVisible="{Binding BiometricButtonVisible}"></Button>
|
||||||
<Button Text="{u:I18n LogOut}" Clicked="LogOut_Clicked"></Button>
|
<Button Text="{u:I18n LogOut}" Clicked="LogOut_Clicked"></Button>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace Bit.App.Pages
|
||||||
private bool _pinLock;
|
private bool _pinLock;
|
||||||
private bool _biometricLock;
|
private bool _biometricLock;
|
||||||
private bool _biometricIntegrityValid = true;
|
private bool _biometricIntegrityValid = true;
|
||||||
|
private bool _biometricButtonVisible = true;
|
||||||
private string _biometricButtonText;
|
private string _biometricButtonText;
|
||||||
private string _loggedInAsText;
|
private string _loggedInAsText;
|
||||||
private string _lockedVerifyText;
|
private string _lockedVerifyText;
|
||||||
|
@ -87,6 +88,12 @@ namespace Bit.App.Pages
|
||||||
set => SetProperty(ref _biometricIntegrityValid, value);
|
set => SetProperty(ref _biometricIntegrityValid, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool BiometricButtonVisible
|
||||||
|
{
|
||||||
|
get => _biometricButtonVisible;
|
||||||
|
set => SetProperty(ref _biometricButtonVisible, value);
|
||||||
|
}
|
||||||
|
|
||||||
public string BiometricButtonText
|
public string BiometricButtonText
|
||||||
{
|
{
|
||||||
get => _biometricButtonText;
|
get => _biometricButtonText;
|
||||||
|
@ -138,6 +145,13 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
if (BiometricLock)
|
if (BiometricLock)
|
||||||
{
|
{
|
||||||
|
BiometricIntegrityValid = await _biometricService.ValidateIntegrityAsync();
|
||||||
|
if (!_biometricIntegrityValid)
|
||||||
|
{
|
||||||
|
BiometricButtonVisible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BiometricButtonVisible = true;
|
||||||
BiometricButtonText = AppResources.UseBiometricsToUnlock;
|
BiometricButtonText = AppResources.UseBiometricsToUnlock;
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
if (Device.RuntimePlatform == Device.iOS)
|
||||||
{
|
{
|
||||||
|
@ -145,8 +159,7 @@ namespace Bit.App.Pages
|
||||||
BiometricButtonText = supportsFace ? AppResources.UseFaceIDToUnlock :
|
BiometricButtonText = supportsFace ? AppResources.UseFaceIDToUnlock :
|
||||||
AppResources.UseFingerprintToUnlock;
|
AppResources.UseFingerprintToUnlock;
|
||||||
}
|
}
|
||||||
BiometricIntegrityValid = await _biometricService.ValidateIntegrityAsync();
|
if (autoPromptBiometric)
|
||||||
if (autoPromptBiometric & _biometricIntegrityValid)
|
|
||||||
{
|
{
|
||||||
var tasks = Task.Run(async () =>
|
var tasks = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,9 +22,11 @@ namespace Bit.iOS.Core.Controllers
|
||||||
private IStorageService _storageService;
|
private IStorageService _storageService;
|
||||||
private IStorageService _secureStorageService;
|
private IStorageService _secureStorageService;
|
||||||
private IPlatformUtilsService _platformUtilsService;
|
private IPlatformUtilsService _platformUtilsService;
|
||||||
|
private IBiometricService _biometricService;
|
||||||
private Tuple<bool, bool> _pinSet;
|
private Tuple<bool, bool> _pinSet;
|
||||||
private bool _pinLock;
|
private bool _pinLock;
|
||||||
private bool _fingerprintLock;
|
private bool _biometricLock;
|
||||||
|
private bool _biometricIntegrityValid = true;
|
||||||
private int _invalidPinAttempts;
|
private int _invalidPinAttempts;
|
||||||
|
|
||||||
public LockPasswordViewController(IntPtr handle)
|
public LockPasswordViewController(IntPtr handle)
|
||||||
|
@ -49,10 +51,12 @@ namespace Bit.iOS.Core.Controllers
|
||||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
|
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
|
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
|
||||||
|
|
||||||
_pinSet = _vaultTimeoutService.IsPinLockSetAsync().GetAwaiter().GetResult();
|
_pinSet = _vaultTimeoutService.IsPinLockSetAsync().GetAwaiter().GetResult();
|
||||||
_pinLock = (_pinSet.Item1 && _vaultTimeoutService.PinProtectedKey != null) || _pinSet.Item2;
|
_pinLock = (_pinSet.Item1 && _vaultTimeoutService.PinProtectedKey != null) || _pinSet.Item2;
|
||||||
_fingerprintLock = _vaultTimeoutService.IsBiometricLockSetAsync().GetAwaiter().GetResult();
|
_biometricLock = _vaultTimeoutService.IsBiometricLockSetAsync().GetAwaiter().GetResult() &&
|
||||||
|
_cryptoService.HasKeyAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
BaseNavItem.Title = _pinLock ? AppResources.VerifyPIN : AppResources.VerifyMasterPassword;
|
BaseNavItem.Title = _pinLock ? AppResources.VerifyPIN : AppResources.VerifyMasterPassword;
|
||||||
BaseCancelButton.Title = AppResources.Cancel;
|
BaseCancelButton.Title = AppResources.Cancel;
|
||||||
|
@ -80,12 +84,17 @@ namespace Bit.iOS.Core.Controllers
|
||||||
|
|
||||||
base.ViewDidLoad();
|
base.ViewDidLoad();
|
||||||
|
|
||||||
if (_fingerprintLock)
|
if (_biometricLock)
|
||||||
{
|
{
|
||||||
|
_biometricIntegrityValid = _biometricService.ValidateIntegrityAsync().GetAwaiter().GetResult();
|
||||||
|
if (!_biometricIntegrityValid)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
var tasks = Task.Run(async () =>
|
var tasks = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
NSRunLoop.Main.BeginInvokeOnMainThread(async () => await PromptFingerprintAsync());
|
NSRunLoop.Main.BeginInvokeOnMainThread(async () => await PromptBiometricAsync());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +102,7 @@ namespace Bit.iOS.Core.Controllers
|
||||||
public override void ViewDidAppear(bool animated)
|
public override void ViewDidAppear(bool animated)
|
||||||
{
|
{
|
||||||
base.ViewDidAppear(animated);
|
base.ViewDidAppear(animated);
|
||||||
if (!_fingerprintLock)
|
if (!_biometricLock || !_biometricIntegrityValid)
|
||||||
{
|
{
|
||||||
MasterPasswordCell.TextField.BecomeFirstResponder();
|
MasterPasswordCell.TextField.BecomeFirstResponder();
|
||||||
}
|
}
|
||||||
|
@ -210,9 +219,9 @@ namespace Bit.iOS.Core.Controllers
|
||||||
Success();
|
Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PromptFingerprintAsync()
|
public async Task PromptBiometricAsync()
|
||||||
{
|
{
|
||||||
if (!_fingerprintLock)
|
if (!_biometricLock || !_biometricIntegrityValid)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -261,11 +270,22 @@ namespace Bit.iOS.Core.Controllers
|
||||||
{
|
{
|
||||||
if (indexPath.Row == 0)
|
if (indexPath.Row == 0)
|
||||||
{
|
{
|
||||||
var biometricButtonText = _controller._deviceActionService.SupportsFaceBiometric() ?
|
|
||||||
AppResources.UseFaceIDToUnlock : AppResources.UseFingerprintToUnlock;
|
|
||||||
var cell = new ExtendedUITableViewCell();
|
var cell = new ExtendedUITableViewCell();
|
||||||
cell.TextLabel.TextColor = ThemeHelpers.PrimaryColor;
|
if (_controller._biometricIntegrityValid)
|
||||||
cell.TextLabel.Text = biometricButtonText;
|
{
|
||||||
|
var biometricButtonText = _controller._deviceActionService.SupportsFaceBiometric() ?
|
||||||
|
AppResources.UseFaceIDToUnlock : AppResources.UseFingerprintToUnlock;
|
||||||
|
cell.TextLabel.TextColor = ThemeHelpers.PrimaryColor;
|
||||||
|
cell.TextLabel.Text = biometricButtonText;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell.TextLabel.TextColor = ThemeHelpers.DangerColor;
|
||||||
|
cell.TextLabel.Font = ThemeHelpers.GetDangerFont();
|
||||||
|
cell.TextLabel.Lines = 0;
|
||||||
|
cell.TextLabel.LineBreakMode = UILineBreakMode.WordWrap;
|
||||||
|
cell.TextLabel.Text = AppResources.BiometricInvalidated;
|
||||||
|
}
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,7 +299,7 @@ namespace Bit.iOS.Core.Controllers
|
||||||
|
|
||||||
public override nint NumberOfSections(UITableView tableView)
|
public override nint NumberOfSections(UITableView tableView)
|
||||||
{
|
{
|
||||||
return _controller._fingerprintLock ? 2 : 1;
|
return _controller._biometricLock ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override nint RowsInSection(UITableView tableview, nint section)
|
public override nint RowsInSection(UITableView tableview, nint section)
|
||||||
|
@ -307,7 +327,7 @@ namespace Bit.iOS.Core.Controllers
|
||||||
tableView.EndEditing(true);
|
tableView.EndEditing(true);
|
||||||
if (indexPath.Section == 1 && indexPath.Row == 0)
|
if (indexPath.Section == 1 && indexPath.Row == 0)
|
||||||
{
|
{
|
||||||
var task = _controller.PromptFingerprintAsync();
|
var task = _controller.PromptBiometricAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var cell = tableView.CellAt(indexPath);
|
var cell = tableView.CellAt(indexPath);
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace Bit.iOS.Core.Utilities
|
||||||
public static UIColor BackgroundColor = Xamarin.Forms.Color.FromHex("#ffffff").ToUIColor();
|
public static UIColor BackgroundColor = Xamarin.Forms.Color.FromHex("#ffffff").ToUIColor();
|
||||||
public static UIColor MutedColor = Xamarin.Forms.Color.FromHex("#777777").ToUIColor();
|
public static UIColor MutedColor = Xamarin.Forms.Color.FromHex("#777777").ToUIColor();
|
||||||
public static UIColor SuccessColor = Xamarin.Forms.Color.FromHex("#00a65a").ToUIColor();
|
public static UIColor SuccessColor = Xamarin.Forms.Color.FromHex("#00a65a").ToUIColor();
|
||||||
|
public static UIColor DangerColor = Xamarin.Forms.Color.FromHex("dd4b39").ToUIColor();
|
||||||
public static UIColor PrimaryColor = Xamarin.Forms.Color.FromHex("#175DDC").ToUIColor();
|
public static UIColor PrimaryColor = Xamarin.Forms.Color.FromHex("#175DDC").ToUIColor();
|
||||||
public static UIColor TextColor = Xamarin.Forms.Color.FromHex("#000000").ToUIColor();
|
public static UIColor TextColor = Xamarin.Forms.Color.FromHex("#000000").ToUIColor();
|
||||||
public static UIColor PlaceholderColor = Xamarin.Forms.Color.FromHex("#d0d0d0").ToUIColor();
|
public static UIColor PlaceholderColor = Xamarin.Forms.Color.FromHex("#d0d0d0").ToUIColor();
|
||||||
|
@ -56,6 +57,12 @@ namespace Bit.iOS.Core.Utilities
|
||||||
UILabel.AppearanceWhenContainedIn(typeof(UITableViewHeaderFooterView)).TextColor = MutedColor;
|
UILabel.AppearanceWhenContainedIn(typeof(UITableViewHeaderFooterView)).TextColor = MutedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UIFont GetDangerFont()
|
||||||
|
{
|
||||||
|
return Xamarin.Forms.Font.SystemFontOfSize(Xamarin.Forms.NamedSize.Small,
|
||||||
|
Xamarin.Forms.FontAttributes.Bold).ToUIFont();
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetThemeVariables(string theme)
|
private static void SetThemeVariables(string theme)
|
||||||
{
|
{
|
||||||
LightTheme = false;
|
LightTheme = false;
|
||||||
|
@ -69,6 +76,7 @@ namespace Bit.iOS.Core.Utilities
|
||||||
var whiteColor = Xamarin.Forms.Color.FromHex("#ffffff").ToUIColor();
|
var whiteColor = Xamarin.Forms.Color.FromHex("#ffffff").ToUIColor();
|
||||||
MutedColor = Xamarin.Forms.Color.FromHex("#a3a3a3").ToUIColor();
|
MutedColor = Xamarin.Forms.Color.FromHex("#a3a3a3").ToUIColor();
|
||||||
SuccessColor = Xamarin.Forms.Color.FromHex("#00a65a").ToUIColor();
|
SuccessColor = Xamarin.Forms.Color.FromHex("#00a65a").ToUIColor();
|
||||||
|
DangerColor = Xamarin.Forms.Color.FromHex("ff3e24").ToUIColor();
|
||||||
BackgroundColor = Xamarin.Forms.Color.FromHex("#303030").ToUIColor();
|
BackgroundColor = Xamarin.Forms.Color.FromHex("#303030").ToUIColor();
|
||||||
SplashBackgroundColor = Xamarin.Forms.Color.FromHex("#222222").ToUIColor();
|
SplashBackgroundColor = Xamarin.Forms.Color.FromHex("#222222").ToUIColor();
|
||||||
PrimaryColor = Xamarin.Forms.Color.FromHex("#52bdfb").ToUIColor();
|
PrimaryColor = Xamarin.Forms.Color.FromHex("#52bdfb").ToUIColor();
|
||||||
|
@ -85,6 +93,7 @@ namespace Bit.iOS.Core.Utilities
|
||||||
var whiteColor = Xamarin.Forms.Color.FromHex("#ffffff").ToUIColor();
|
var whiteColor = Xamarin.Forms.Color.FromHex("#ffffff").ToUIColor();
|
||||||
MutedColor = Xamarin.Forms.Color.FromHex("#a3a3a3").ToUIColor();
|
MutedColor = Xamarin.Forms.Color.FromHex("#a3a3a3").ToUIColor();
|
||||||
SuccessColor = Xamarin.Forms.Color.FromHex("#00a65a").ToUIColor();
|
SuccessColor = Xamarin.Forms.Color.FromHex("#00a65a").ToUIColor();
|
||||||
|
DangerColor = Xamarin.Forms.Color.FromHex("ff3e24").ToUIColor();
|
||||||
BackgroundColor = blackColor;
|
BackgroundColor = blackColor;
|
||||||
SplashBackgroundColor = blackColor;
|
SplashBackgroundColor = blackColor;
|
||||||
PrimaryColor = Xamarin.Forms.Color.FromHex("#52bdfb").ToUIColor();
|
PrimaryColor = Xamarin.Forms.Color.FromHex("#52bdfb").ToUIColor();
|
||||||
|
@ -99,6 +108,7 @@ namespace Bit.iOS.Core.Utilities
|
||||||
{
|
{
|
||||||
MutedColor = Xamarin.Forms.Color.FromHex("#d8dee9").ToUIColor();
|
MutedColor = Xamarin.Forms.Color.FromHex("#d8dee9").ToUIColor();
|
||||||
SuccessColor = Xamarin.Forms.Color.FromHex("#a3be8c").ToUIColor();
|
SuccessColor = Xamarin.Forms.Color.FromHex("#a3be8c").ToUIColor();
|
||||||
|
DangerColor = Xamarin.Forms.Color.FromHex("bf616a").ToUIColor();
|
||||||
BackgroundColor = Xamarin.Forms.Color.FromHex("#3b4252").ToUIColor();
|
BackgroundColor = Xamarin.Forms.Color.FromHex("#3b4252").ToUIColor();
|
||||||
SplashBackgroundColor = Xamarin.Forms.Color.FromHex("#2e3440").ToUIColor();
|
SplashBackgroundColor = Xamarin.Forms.Color.FromHex("#2e3440").ToUIColor();
|
||||||
PrimaryColor = Xamarin.Forms.Color.FromHex("#81a1c1").ToUIColor();
|
PrimaryColor = Xamarin.Forms.Color.FromHex("#81a1c1").ToUIColor();
|
||||||
|
|
Loading…
Reference in a new issue