mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 18:08:26 +03:00
log out after 5 failed pin attempts
This commit is contained in:
parent
1390df48b6
commit
53f406a267
14 changed files with 55 additions and 12 deletions
|
@ -139,7 +139,14 @@ namespace Bit.Android
|
||||||
|
|
||||||
if(Utilities.NfcEnabled())
|
if(Utilities.NfcEnabled())
|
||||||
{
|
{
|
||||||
MessagingCenter.Send(Xamarin.Forms.Application.Current, "ResumeYubiKey");
|
try
|
||||||
|
{
|
||||||
|
MessagingCenter.Send(Xamarin.Forms.Application.Current, "ResumeYubiKey");
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace Bit.App.Abstractions
|
||||||
public interface IAppSettingsService
|
public interface IAppSettingsService
|
||||||
{
|
{
|
||||||
bool Locked { get; set; }
|
bool Locked { get; set; }
|
||||||
|
int FailedPinAttempts { get; set; }
|
||||||
DateTime LastActivity { get; set; }
|
DateTime LastActivity { get; set; }
|
||||||
DateTime LastCacheClear { get; set; }
|
DateTime LastCacheClear { get; set; }
|
||||||
bool AutofillPersistNotification { get; set; }
|
bool AutofillPersistNotification { get; set; }
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
public const string ApiUrl = "other:apiUrl";
|
public const string ApiUrl = "other:apiUrl";
|
||||||
public const string IdentityUrl = "other:identityUrl";
|
public const string IdentityUrl = "other:identityUrl";
|
||||||
public const string IconsUrl = "other:iconsUrl";
|
public const string IconsUrl = "other:iconsUrl";
|
||||||
|
public const string FailedPinAttempts = "other:failedPinAttempts";
|
||||||
|
|
||||||
public const int SelectFileRequestCode = 42;
|
public const int SelectFileRequestCode = 42;
|
||||||
public const int SelectFilePermissionRequestCode = 43;
|
public const int SelectFilePermissionRequestCode = 43;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Pages;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
@ -10,23 +11,33 @@ namespace Bit.App.Controls
|
||||||
private IGoogleAnalyticsService _googleAnalyticsService;
|
private IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
private ILockService _lockService;
|
private ILockService _lockService;
|
||||||
private IDeviceActionService _deviceActionService;
|
private IDeviceActionService _deviceActionService;
|
||||||
|
private IAuthService _authService;
|
||||||
private bool _syncIndicator;
|
private bool _syncIndicator;
|
||||||
private bool _updateActivity;
|
private bool _updateActivity;
|
||||||
|
private bool _requireAuth;
|
||||||
|
|
||||||
public ExtendedContentPage(bool syncIndicator = false, bool updateActivity = true)
|
public ExtendedContentPage(bool syncIndicator = false, bool updateActivity = true, bool requireAuth = true)
|
||||||
{
|
{
|
||||||
_syncIndicator = syncIndicator;
|
_syncIndicator = syncIndicator;
|
||||||
_updateActivity = updateActivity;
|
_updateActivity = updateActivity;
|
||||||
|
_requireAuth = requireAuth;
|
||||||
_syncService = Resolver.Resolve<ISyncService>();
|
_syncService = Resolver.Resolve<ISyncService>();
|
||||||
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
||||||
_lockService = Resolver.Resolve<ILockService>();
|
_lockService = Resolver.Resolve<ILockService>();
|
||||||
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
|
|
||||||
BackgroundColor = Color.FromHex("efeff4");
|
BackgroundColor = Color.FromHex("efeff4");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
|
if(_requireAuth && !_authService.IsAuthenticated)
|
||||||
|
{
|
||||||
|
Device.BeginInvokeOnMainThread(
|
||||||
|
() => Application.Current.MainPage = new ExtendedNavigationPage(new HomePage()));
|
||||||
|
}
|
||||||
|
|
||||||
if(_syncIndicator)
|
if(_syncIndicator)
|
||||||
{
|
{
|
||||||
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted",
|
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted",
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Bit.App.Pages
|
||||||
private IGoogleAnalyticsService _googleAnalyticsService;
|
private IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
|
|
||||||
public EnvironmentPage()
|
public EnvironmentPage()
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_appSettings = Resolver.Resolve<IAppSettingsService>();
|
_appSettings = Resolver.Resolve<IAppSettingsService>();
|
||||||
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Bit.App.Pages
|
||||||
private DateTime? _lastAction;
|
private DateTime? _lastAction;
|
||||||
|
|
||||||
public HomePage()
|
public HomePage()
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_authService = Resolver.Resolve<IAuthService>();
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
|
|
@ -124,12 +124,19 @@ namespace Bit.App.Pages
|
||||||
if(Model.PIN == _authService.PIN)
|
if(Model.PIN == _authService.PIN)
|
||||||
{
|
{
|
||||||
_appSettingsService.Locked = false;
|
_appSettingsService.Locked = false;
|
||||||
|
_appSettingsService.FailedPinAttempts = 0;
|
||||||
PinControl.Entry.Unfocus();
|
PinControl.Entry.Unfocus();
|
||||||
await Navigation.PopModalAsync();
|
await Navigation.PopModalAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: keep track of invalid attempts and logout?
|
_appSettingsService.FailedPinAttempts++;
|
||||||
|
if(_appSettingsService.FailedPinAttempts >= 5)
|
||||||
|
{
|
||||||
|
PinControl.Entry.Unfocus();
|
||||||
|
AuthService.LogOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await DisplayAlert(null, AppResources.InvalidPIN, AppResources.Ok);
|
await DisplayAlert(null, AppResources.InvalidPIN, AppResources.Ok);
|
||||||
Model.PIN = string.Empty;
|
Model.PIN = string.Empty;
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Bit.App.Pages
|
||||||
private readonly string _email;
|
private readonly string _email;
|
||||||
|
|
||||||
public LoginPage(string email = null)
|
public LoginPage(string email = null)
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_email = email;
|
_email = email;
|
||||||
_authService = Resolver.Resolve<IAuthService>();
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace Bit.App.Pages
|
||||||
private readonly FullLoginResult _result;
|
private readonly FullLoginResult _result;
|
||||||
|
|
||||||
public LoginTwoFactorPage(string email, FullLoginResult result, TwoFactorProviderType? type = null)
|
public LoginTwoFactorPage(string email, FullLoginResult result, TwoFactorProviderType? type = null)
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Bit.App.Pages
|
||||||
private IDeviceActionService _deviceActionService;
|
private IDeviceActionService _deviceActionService;
|
||||||
|
|
||||||
public PasswordHintPage()
|
public PasswordHintPage()
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_accountApiRepository = Resolver.Resolve<IAccountsApiRepository>();
|
_accountApiRepository = Resolver.Resolve<IAccountsApiRepository>();
|
||||||
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Bit.App.Pages
|
||||||
private HomePage _homePage;
|
private HomePage _homePage;
|
||||||
|
|
||||||
public RegisterPage(HomePage homePage)
|
public RegisterPage(HomePage homePage)
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_homePage = homePage;
|
_homePage = homePage;
|
||||||
_cryptoService = Resolver.Resolve<ICryptoService>();
|
_cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Bit.App.Pages
|
||||||
private bool _pageDisappeared = true;
|
private bool _pageDisappeared = true;
|
||||||
|
|
||||||
public ScanPage(Action<string> callback)
|
public ScanPage(Action<string> callback)
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false, requireAuth: false)
|
||||||
{
|
{
|
||||||
_zxing = new ZXingScannerView
|
_zxing = new ZXingScannerView
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,18 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int FailedPinAttempts
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _settings.GetValueOrDefault(Constants.FailedPinAttempts, 0);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_settings.AddOrUpdateValue(Constants.FailedPinAttempts, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DateTime LastActivity
|
public DateTime LastActivity
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace Bit.App.Services
|
||||||
private readonly ISecureStorageService _secureStorage;
|
private readonly ISecureStorageService _secureStorage;
|
||||||
private readonly ITokenService _tokenService;
|
private readonly ITokenService _tokenService;
|
||||||
private readonly ISettings _settings;
|
private readonly ISettings _settings;
|
||||||
|
private readonly IAppSettingsService _appSettingsService;
|
||||||
private readonly ICryptoService _cryptoService;
|
private readonly ICryptoService _cryptoService;
|
||||||
private readonly IConnectApiRepository _connectApiRepository;
|
private readonly IConnectApiRepository _connectApiRepository;
|
||||||
private readonly IAccountsApiRepository _accountsApiRepository;
|
private readonly IAccountsApiRepository _accountsApiRepository;
|
||||||
|
@ -41,6 +42,7 @@ namespace Bit.App.Services
|
||||||
ISecureStorageService secureStorage,
|
ISecureStorageService secureStorage,
|
||||||
ITokenService tokenService,
|
ITokenService tokenService,
|
||||||
ISettings settings,
|
ISettings settings,
|
||||||
|
IAppSettingsService appSettingsService,
|
||||||
ICryptoService cryptoService,
|
ICryptoService cryptoService,
|
||||||
IConnectApiRepository connectApiRepository,
|
IConnectApiRepository connectApiRepository,
|
||||||
IAccountsApiRepository accountsApiRepository,
|
IAccountsApiRepository accountsApiRepository,
|
||||||
|
@ -52,6 +54,7 @@ namespace Bit.App.Services
|
||||||
_secureStorage = secureStorage;
|
_secureStorage = secureStorage;
|
||||||
_tokenService = tokenService;
|
_tokenService = tokenService;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_appSettingsService = appSettingsService;
|
||||||
_cryptoService = cryptoService;
|
_cryptoService = cryptoService;
|
||||||
_connectApiRepository = connectApiRepository;
|
_connectApiRepository = connectApiRepository;
|
||||||
_accountsApiRepository = accountsApiRepository;
|
_accountsApiRepository = accountsApiRepository;
|
||||||
|
@ -269,10 +272,10 @@ namespace Bit.App.Services
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Models.LoginResult> TokenPostTwoFactorAsync(TwoFactorProviderType type, string token, bool remember,
|
public async Task<LoginResult> TokenPostTwoFactorAsync(TwoFactorProviderType type, string token, bool remember,
|
||||||
string email, string masterPasswordHash, SymmetricCryptoKey key)
|
string email, string masterPasswordHash, SymmetricCryptoKey key)
|
||||||
{
|
{
|
||||||
var result = new Models.LoginResult();
|
var result = new LoginResult();
|
||||||
|
|
||||||
var request = new TokenRequest
|
var request = new TokenRequest
|
||||||
{
|
{
|
||||||
|
@ -315,6 +318,7 @@ namespace Bit.App.Services
|
||||||
UserId = _tokenService.TokenUserId;
|
UserId = _tokenService.TokenUserId;
|
||||||
Email = _tokenService.TokenEmail;
|
Email = _tokenService.TokenEmail;
|
||||||
_settings.AddOrUpdateValue(Constants.LastLoginEmail, Email);
|
_settings.AddOrUpdateValue(Constants.LastLoginEmail, Email);
|
||||||
|
_appSettingsService.FailedPinAttempts = 0;
|
||||||
|
|
||||||
if(response.PrivateKey != null)
|
if(response.PrivateKey != null)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue