mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-15 10:25:20 +01:00
PM-6706 Add maximum attempts to UV with MP and with PIN (#3079)
This commit is contained in:
parent
970d3c2621
commit
39da2a82c6
@ -9,6 +9,6 @@ namespace Bit.Core.Abstractions
|
||||
Task<bool> ShouldPerformMasterPasswordRepromptAsync(Fido2UserVerificationOptions options);
|
||||
Task<(bool CanPerfom, bool IsUnlocked)> PerformOSUnlockAsync();
|
||||
Task<(bool canPerformUnlockWithPin, bool pinVerified)> VerifyPinCodeAsync();
|
||||
Task<(bool canPerformUnlockWithMasterPassword, bool mpVerified)> VerifyMasterPasswordAsync();
|
||||
Task<(bool canPerformUnlockWithMasterPassword, bool mpVerified)> VerifyMasterPasswordAsync(bool isMasterPasswordReprompt);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace Bit.Core.Services.UserVerification
|
||||
return pinVerified;
|
||||
}
|
||||
|
||||
var (canPerformUnlockWithMasterPassword, mpVerified) = await _userVerificationMediatorService.VerifyMasterPasswordAsync();
|
||||
var (canPerformUnlockWithMasterPassword, mpVerified) = await _userVerificationMediatorService.VerifyMasterPasswordAsync(false);
|
||||
if (canPerformUnlockWithMasterPassword)
|
||||
{
|
||||
return mpVerified;
|
||||
|
@ -10,6 +10,8 @@ namespace Bit.Core.Services.UserVerification
|
||||
{
|
||||
public class UserVerificationMediatorService : IUserVerificationMediatorService
|
||||
{
|
||||
private const byte MAX_ATTEMPTS = 5;
|
||||
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
private readonly IPasswordRepromptService _passwordRepromptService;
|
||||
private readonly IUserPinService _userPinService;
|
||||
@ -44,7 +46,8 @@ namespace Bit.Core.Services.UserVerification
|
||||
await options.OnNeedUITask();
|
||||
}
|
||||
|
||||
return await _passwordRepromptService.PromptAndCheckPasswordIfNeededAsync(Enums.CipherRepromptType.Password);
|
||||
var (canPerformMP, mpVerified) = await VerifyMasterPasswordAsync(true);
|
||||
return canPerformMP && mpVerified;
|
||||
}
|
||||
|
||||
if (!_fido2UserVerificationStrategies.TryGetValue(options.UserVerificationPreference, out var userVerificationServiceStrategy))
|
||||
@ -95,43 +98,71 @@ namespace Bit.Core.Services.UserVerification
|
||||
|
||||
public async Task<(bool canPerformUnlockWithPin, bool pinVerified)> VerifyPinCodeAsync()
|
||||
{
|
||||
if (!await _userPinService.IsPinLockEnabledAsync())
|
||||
return await VerifyWithAttemptsAsync(async () =>
|
||||
{
|
||||
return (false, false);
|
||||
}
|
||||
if (!await _userPinService.IsPinLockEnabledAsync())
|
||||
{
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
var pin = await _deviceActionService.DisplayPromptAync(AppResources.EnterPIN,
|
||||
AppResources.VerifyPIN, null, AppResources.Ok, AppResources.Cancel, password: true);
|
||||
if (pin is null)
|
||||
{
|
||||
// cancelled by the user
|
||||
return (true, false);
|
||||
}
|
||||
var pin = await _deviceActionService.DisplayPromptAync(AppResources.EnterPIN,
|
||||
AppResources.VerifyPIN, null, AppResources.Ok, AppResources.Cancel, password: true);
|
||||
if (pin is null)
|
||||
{
|
||||
// cancelled by the user
|
||||
return (true, false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var isVerified = await _userPinService.VerifyPinAsync(pin);
|
||||
return (true, isVerified);
|
||||
}
|
||||
catch (SymmetricCryptoKey.ArgumentKeyNullException)
|
||||
{
|
||||
return (true, false);
|
||||
}
|
||||
catch (SymmetricCryptoKey.InvalidKeyOperationException)
|
||||
{
|
||||
return (true, false);
|
||||
}
|
||||
try
|
||||
{
|
||||
var isVerified = await _userPinService.VerifyPinAsync(pin);
|
||||
return (true, isVerified);
|
||||
}
|
||||
catch (SymmetricCryptoKey.ArgumentKeyNullException)
|
||||
{
|
||||
return (true, false);
|
||||
}
|
||||
catch (SymmetricCryptoKey.InvalidKeyOperationException)
|
||||
{
|
||||
return (true, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<(bool canPerformUnlockWithMasterPassword, bool mpVerified)> VerifyMasterPasswordAsync()
|
||||
public async Task<(bool canPerformUnlockWithMasterPassword, bool mpVerified)> VerifyMasterPasswordAsync(bool isMasterPasswordReprompt)
|
||||
{
|
||||
if (!await _userVerificationService.HasMasterPasswordAsync(true))
|
||||
return await VerifyWithAttemptsAsync(async () =>
|
||||
{
|
||||
return (false, false);
|
||||
}
|
||||
if (!await _userVerificationService.HasMasterPasswordAsync(true))
|
||||
{
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
var (_, isValid) = await _platformUtilsService.ShowPasswordDialogAndGetItAsync(AppResources.MasterPassword, string.Empty, _userVerificationService.VerifyMasterPasswordAsync);
|
||||
return (true, isValid);
|
||||
var title = isMasterPasswordReprompt ? AppResources.PasswordConfirmation : AppResources.MasterPassword;
|
||||
var body = isMasterPasswordReprompt ? AppResources.PasswordConfirmationDesc : string.Empty;
|
||||
|
||||
var (_, isValid) = await _platformUtilsService.ShowPasswordDialogAndGetItAsync(title, body, _userVerificationService.VerifyMasterPasswordAsync);
|
||||
return (true, isValid);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<(bool canPerform, bool isVerified)> VerifyWithAttemptsAsync(Func<Task<(bool canPerform, bool isVerified)>> verifyAsync)
|
||||
{
|
||||
byte attempts = 0;
|
||||
do
|
||||
{
|
||||
var (canPerform, verified) = await verifyAsync();
|
||||
if (!canPerform)
|
||||
{
|
||||
return (false, false);
|
||||
}
|
||||
if (verified)
|
||||
{
|
||||
return (true, true);
|
||||
}
|
||||
} while (attempts++ < MAX_ATTEMPTS);
|
||||
|
||||
return (true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user