1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-20 01:13:30 +00:00

Invalidate biometric on change (#1026)

* Initial working version for Android

* Add a fallback for when upgrading from older app version.

* Ensure biometric validity is re-checked on focus

* Only setup biometric integrity key if biometric is turned on.

* Fix styling according to comments

* Fallback for Android 5.

* Improve comment

* Add boilerplate for iOS

* Change BiometricService to public

* Untested iOS implementation.

* Convert IBiometricService to async. Fix code style for iOS.

* Base64 NSData.

* Review comments for Android BiometricService.

* Rename methods in BiometricService to append Async

* Ensure we wait for async SetupBiometricAsync.

* Update BiometricService.cs

Co-authored-by: Kyle Spearrin <kspearrin@users.noreply.github.com>
This commit is contained in:
Oscar Hinton
2020-08-09 03:33:49 +02:00
committed by GitHub
parent 39de2c1d25
commit ae28de4159
12 changed files with 218 additions and 20 deletions

View File

@@ -106,8 +106,12 @@
Margin="0, 10, 0, 0" />
</StackLayout>
<StackLayout Padding="10, 0">
<Label
Text="{u:I18n BiometricInvalidated}"
StyleClass="box-footer-label,text-danger,text-bold"
IsVisible="{Binding BiometricIntegrityValid, Converter={StaticResource inverseBool}}" />
<Button Text="{Binding BiometricButtonText}" Clicked="Biometric_Clicked"
IsVisible="{Binding BiometricLock}"></Button>
IsVisible="{Binding BiometricLock}" IsEnabled="{Binding BiometricIntegrityValid}"></Button>
<Button Text="{u:I18n LogOut}" Clicked="LogOut_Clicked"></Button>
</StackLayout>
</StackLayout>

View File

@@ -24,11 +24,13 @@ namespace Bit.App.Pages
private readonly IStorageService _secureStorageService;
private readonly IEnvironmentService _environmentService;
private readonly IStateService _stateService;
private readonly IBiometricService _biometricService;
private string _email;
private bool _showPassword;
private bool _pinLock;
private bool _biometricLock;
private bool _biometricIntegrityValid = true;
private string _biometricButtonText;
private string _loggedInAsText;
private string _lockedVerifyText;
@@ -47,6 +49,7 @@ namespace Bit.App.Pages
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
PageTitle = AppResources.VerifyMasterPassword;
TogglePasswordCommand = new Command(TogglePassword);
@@ -75,6 +78,12 @@ namespace Bit.App.Pages
set => SetProperty(ref _biometricLock, value);
}
public bool BiometricIntegrityValid
{
get => _biometricIntegrityValid;
set => SetProperty(ref _biometricIntegrityValid, value);
}
public string BiometricButtonText
{
get => _biometricButtonText;
@@ -133,7 +142,8 @@ namespace Bit.App.Pages
BiometricButtonText = supportsFace ? AppResources.UseFaceIDToUnlock :
AppResources.UseFingerprintToUnlock;
}
if (autoPromptBiometric)
BiometricIntegrityValid = await _biometricService.ValidateIntegrityAsync();
if (autoPromptBiometric & _biometricIntegrityValid)
{
var tasks = Task.Run(async () =>
{
@@ -238,6 +248,12 @@ namespace Bit.App.Pages
}
MasterPassword = string.Empty;
await SetKeyAndContinueAsync(key);
// Re-enable biometrics
if (BiometricLock & !BiometricIntegrityValid)
{
await _biometricService.SetupBiometricAsync();
}
}
else
{
@@ -267,7 +283,8 @@ namespace Bit.App.Pages
public async Task PromptBiometricAsync()
{
if (!BiometricLock)
BiometricIntegrityValid = await _biometricService.ValidateIntegrityAsync();
if (!BiometricLock || !BiometricIntegrityValid)
{
return;
}

View File

@@ -22,6 +22,7 @@ namespace Bit.App.Pages
private readonly IVaultTimeoutService _vaultTimeoutService;
private readonly IStorageService _storageService;
private readonly ISyncService _syncService;
private readonly IBiometricService _biometricService;
private bool _supportsBiometric;
private bool _pin;
@@ -60,6 +61,7 @@ namespace Bit.App.Pages
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
PageTitle = AppResources.Settings;
@@ -306,6 +308,7 @@ namespace Bit.App.Pages
}
if (_biometric)
{
await _biometricService.SetupBiometricAsync();
await _storageService.SaveAsync(Constants.BiometricUnlockKey, true);
}
else

View File

@@ -59,46 +59,46 @@
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
@@ -1674,4 +1674,7 @@
<value>Do you really want to send to the bin?</value>
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
</data>
<data name="BiometricInvalidated" xml:space="preserve">
<value>Biometric change detected, login using Master Password to enable again.</value>
</data>
</root>

View File

@@ -1674,6 +1674,9 @@
<value>Do you really want to send to the trash?</value>
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
</data>
<data name="BiometricInvalidated" xml:space="preserve">
<value>Biometric change detected, login using Master Password to enable again.</value>
</data>
<data name="EnableSyncOnRefresh" xml:space="preserve">
<value>Enable sync on refresh</value>
</data>