diff --git a/src/App/Abstractions/Services/IAppSettingsService.cs b/src/App/Abstractions/Services/IAppSettingsService.cs index d04d0e60d..ac96407c7 100644 --- a/src/App/Abstractions/Services/IAppSettingsService.cs +++ b/src/App/Abstractions/Services/IAppSettingsService.cs @@ -8,5 +8,6 @@ namespace Bit.App.Abstractions DateTime LastActivity { get; set; } bool AutofillPersistNotification { get; set; } bool AutofillPasswordField { get; set; } + string SecurityStamp { get; set; } } } \ No newline at end of file diff --git a/src/App/Constants.cs b/src/App/Constants.cs index 7ada15660..6f4a541c6 100644 --- a/src/App/Constants.cs +++ b/src/App/Constants.cs @@ -26,7 +26,7 @@ public const string ExtensionStarted = "extension:started"; public const string ExtensionActivated = "extension:activated"; - public const string FirstVaultLoad = "other:firstVaultLoad"; + public const string SecurityStamp = "other:securityStamp"; public const string LastActivityDate = "other:lastActivityDate"; public const string Locked = "other:locked"; public const string LastLoginEmail = "other:lastLoginEmail"; diff --git a/src/App/Models/Api/Response/ProfileResponse.cs b/src/App/Models/Api/Response/ProfileResponse.cs index e2bc1a6b4..7370d0e5b 100644 --- a/src/App/Models/Api/Response/ProfileResponse.cs +++ b/src/App/Models/Api/Response/ProfileResponse.cs @@ -12,6 +12,7 @@ namespace Bit.App.Models.Api public bool TwoFactorEnabled { get; set; } public string Key { get; set; } public string PrivateKey { get; set; } + public string SecurityStamp { get; set; } public IEnumerable Organizations { get; set; } } } diff --git a/src/App/Services/AppSettingsService.cs b/src/App/Services/AppSettingsService.cs index e3c66320b..312f753c5 100644 --- a/src/App/Services/AppSettingsService.cs +++ b/src/App/Services/AppSettingsService.cs @@ -61,5 +61,17 @@ namespace Bit.App.Services _settings.AddOrUpdateValue(Constants.AutofillPasswordField, value); } } + + public string SecurityStamp + { + get + { + return _settings.GetValueOrDefault(Constants.SecurityStamp); + } + set + { + _settings.AddOrUpdateValue(Constants.SecurityStamp, value); + } + } } } diff --git a/src/App/Services/AuthService.cs b/src/App/Services/AuthService.cs index c96e78a08..711c91b67 100644 --- a/src/App/Services/AuthService.cs +++ b/src/App/Services/AuthService.cs @@ -202,7 +202,7 @@ namespace Bit.App.Services UserId = null; Email = null; _cryptoService.ClearKeys(); - _settings.Remove(Constants.FirstVaultLoad); + _settings.Remove(Constants.SecurityStamp); _settings.Remove(Constants.PushLastRegistrationDate); _settings.Remove(Constants.Locked); } diff --git a/src/App/Services/SyncService.cs b/src/App/Services/SyncService.cs index 5081a7fce..87ddc80b7 100644 --- a/src/App/Services/SyncService.cs +++ b/src/App/Services/SyncService.cs @@ -25,6 +25,7 @@ namespace Bit.App.Services private readonly IAuthService _authService; private readonly ICryptoService _cryptoService; private readonly ISettings _settings; + private readonly IAppSettingsService _appSettingsService; public SyncService( ICipherApiRepository cipherApiRepository, @@ -37,7 +38,8 @@ namespace Bit.App.Services ISettingsRepository settingsRepository, IAuthService authService, ICryptoService cryptoService, - ISettings settings) + ISettings settings, + IAppSettingsService appSettingsService) { _cipherApiRepository = cipherApiRepository; _folderApiRepository = folderApiRepository; @@ -50,6 +52,7 @@ namespace Bit.App.Services _authService = authService; _cryptoService = cryptoService; _settings = settings; + _appSettingsService = appSettingsService; } public bool SyncInProgress { get; private set; } @@ -197,7 +200,8 @@ namespace Bit.App.Services SyncStarted(); var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false); - if(!CheckSuccess(profile)) + if(!CheckSuccess(profile, !string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) && + _appSettingsService.SecurityStamp != profile.Result.SecurityStamp)) { return false; } @@ -238,7 +242,8 @@ namespace Bit.App.Services // Just check profile first to make sure we'll have a success with the API var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false); - if(!CheckSuccess(profile)) + if(!CheckSuccess(profile, !string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) && + _appSettingsService.SecurityStamp != profile.Result.SecurityStamp)) { return false; } @@ -408,6 +413,11 @@ namespace Bit.App.Services _cryptoService.SetPrivateKey(new CipherString(profile.PrivateKey)); } + if(!string.IsNullOrWhiteSpace(profile.SecurityStamp)) + { + _appSettingsService.SecurityStamp = profile.SecurityStamp; + } + _cryptoService.SetOrgKeys(profile); return Task.FromResult(0); } @@ -434,14 +444,15 @@ namespace Bit.App.Services MessagingCenter.Send(Application.Current, "SyncCompleted", successfully); } - private bool CheckSuccess(ApiResult result) + private bool CheckSuccess(ApiResult result, bool logout = false) { - if(!result.Succeeded) + if(!result.Succeeded || logout) { SyncCompleted(false); - if(Application.Current != null && (result.StatusCode == System.Net.HttpStatusCode.Forbidden - || result.StatusCode == System.Net.HttpStatusCode.Unauthorized)) + if(Application.Current != null && (logout || + result.StatusCode == System.Net.HttpStatusCode.Forbidden || + result.StatusCode == System.Net.HttpStatusCode.Unauthorized)) { MessagingCenter.Send(Application.Current, "Logout", (string)null); }