diff --git a/src/App/Abstractions/Services/ISyncService.cs b/src/App/Abstractions/Services/ISyncService.cs index 1e0b5bd64..c0b448a2d 100644 --- a/src/App/Abstractions/Services/ISyncService.cs +++ b/src/App/Abstractions/Services/ISyncService.cs @@ -11,6 +11,7 @@ namespace Bit.App.Abstractions Task SyncDeleteFolderAsync(string id, DateTime revisionDate); Task SyncDeleteLoginAsync(string id); Task SyncSettingsAsync(); + Task SyncProfileAsync(); Task FullSyncAsync(bool forceSync = false); Task FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false); } diff --git a/src/App/Services/PushNotificationListener.cs b/src/App/Services/PushNotificationListener.cs index eacb37575..503916476 100644 --- a/src/App/Services/PushNotificationListener.cs +++ b/src/App/Services/PushNotificationListener.cs @@ -60,11 +60,13 @@ namespace Bit.App.Services case Enums.PushType.SyncCipherUpdate: case Enums.PushType.SyncCipherCreate: var cipherCreateUpdateMessage = values.ToObject(); - if(cipherCreateUpdateMessage.UserId != null && cipherCreateUpdateMessage.UserId != _authService.UserId) + if(cipherCreateUpdateMessage.OrganizationId == null && + cipherCreateUpdateMessage.UserId != _authService.UserId) { break; } - else if(!_authService.BelongsToOrganization(cipherCreateUpdateMessage.OrganizationId)) + else if(cipherCreateUpdateMessage.OrganizationId != null && + !_authService.BelongsToOrganization(cipherCreateUpdateMessage.OrganizationId)) { break; } @@ -89,11 +91,13 @@ namespace Bit.App.Services break; case Enums.PushType.SyncLoginDelete: var loginDeleteMessage = values.ToObject(); - if(loginDeleteMessage.UserId != null && loginDeleteMessage.UserId != _authService.UserId) + if(loginDeleteMessage.OrganizationId == null && + loginDeleteMessage.UserId != _authService.UserId) { break; } - else if(!_authService.BelongsToOrganization(loginDeleteMessage.OrganizationId)) + else if(loginDeleteMessage.OrganizationId != null && + !_authService.BelongsToOrganization(loginDeleteMessage.OrganizationId)) { break; } @@ -116,6 +120,14 @@ namespace Bit.App.Services } _syncService.SyncSettingsAsync(); break; + case Enums.PushType.SyncOrgKeys: + var orgKeysMessage = values.ToObject(); + if(orgKeysMessage.UserId != _authService.UserId) + { + break; + } + _syncService.SyncProfileAsync(); + break; default: break; } diff --git a/src/App/Services/SyncService.cs b/src/App/Services/SyncService.cs index 9025e70ad..d45c24250 100644 --- a/src/App/Services/SyncService.cs +++ b/src/App/Services/SyncService.cs @@ -8,6 +8,8 @@ using Bit.App.Models.Api; using System.Collections.Generic; using Xamarin.Forms; using Newtonsoft.Json; +using Bit.App.Models; +using System.Diagnostics; namespace Bit.App.Services { @@ -22,6 +24,7 @@ namespace Bit.App.Services private readonly ILoginRepository _loginRepository; private readonly ISettingsRepository _settingsRepository; private readonly IAuthService _authService; + private readonly ICryptoService _cryptoService; private readonly ISettings _settings; public SyncService( @@ -34,6 +37,7 @@ namespace Bit.App.Services ILoginRepository loginRepository, ISettingsRepository settingsRepository, IAuthService authService, + ICryptoService cryptoService, ISettings settings) { _cipherApiRepository = cipherApiRepository; @@ -45,6 +49,7 @@ namespace Bit.App.Services _loginRepository = loginRepository; _settingsRepository = settingsRepository; _authService = authService; + _cryptoService = cryptoService; _settings = settings; } @@ -60,16 +65,8 @@ namespace Bit.App.Services SyncStarted(); var cipher = await _cipherApiRepository.GetByIdAsync(id).ConfigureAwait(false); - if(!cipher.Succeeded) + if(!CheckSuccess(cipher)) { - SyncCompleted(false); - - if(Application.Current != null && (cipher.StatusCode == System.Net.HttpStatusCode.Forbidden - || cipher.StatusCode == System.Net.HttpStatusCode.Unauthorized)) - { - MessagingCenter.Send(Application.Current, "Logout", (string)null); - } - return false; } @@ -106,16 +103,8 @@ namespace Bit.App.Services SyncStarted(); var folder = await _folderApiRepository.GetByIdAsync(id).ConfigureAwait(false); - if(!folder.Succeeded) + if(!CheckSuccess(folder)) { - SyncCompleted(false); - - if(Application.Current != null && (folder.StatusCode == System.Net.HttpStatusCode.Forbidden - || folder.StatusCode == System.Net.HttpStatusCode.Unauthorized)) - { - MessagingCenter.Send(Application.Current, "Logout", (string)null); - } - return false; } @@ -188,16 +177,8 @@ namespace Bit.App.Services SyncStarted(); var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false); - if(!domains.Succeeded) + if(!CheckSuccess(domains)) { - SyncCompleted(false); - - if(Application.Current != null && (domains.StatusCode == System.Net.HttpStatusCode.Forbidden - || domains.StatusCode == System.Net.HttpStatusCode.Unauthorized)) - { - MessagingCenter.Send(Application.Current, "Logout", (string)null); - } - return false; } @@ -206,6 +187,26 @@ namespace Bit.App.Services SyncCompleted(true); return true; } + public async Task SyncProfileAsync() + { + if(!_authService.IsAuthenticated) + { + return false; + } + + SyncStarted(); + + var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false); + if(!CheckSuccess(profile)) + { + return false; + } + + SyncOrgKeys(profile.Result); + + SyncCompleted(true); + return true; + } public async Task FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false) { @@ -234,26 +235,19 @@ namespace Bit.App.Services SyncStarted(); var now = DateTime.UtcNow; + + // 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)) + { + return false; + } + var ciphers = await _cipherApiRepository.GetAsync().ConfigureAwait(false); var folders = await _folderApiRepository.GetAsync().ConfigureAwait(false); var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false); - - if(!ciphers.Succeeded || !domains.Succeeded) + if(!CheckSuccess(ciphers) || !CheckSuccess(folders) || !CheckSuccess(domains)) { - SyncCompleted(false); - if(Application.Current == null) - { - return false; - } - - if(ciphers.StatusCode == System.Net.HttpStatusCode.Forbidden || - ciphers.StatusCode == System.Net.HttpStatusCode.Unauthorized || - domains.StatusCode == System.Net.HttpStatusCode.Forbidden || - domains.StatusCode == System.Net.HttpStatusCode.Unauthorized) - { - MessagingCenter.Send(Application.Current, "Logout", (string)null); - } - return false; } @@ -263,6 +257,7 @@ namespace Bit.App.Services var loginTask = SyncLoginsAsync(loginsDict); var folderTask = SyncFoldersAsync(foldersDict); var domainsTask = SyncDomainsAsync(domains.Result); + SyncOrgKeys(profile.Result); await Task.WhenAll(loginTask, folderTask, domainsTask).ConfigureAwait(false); if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null) @@ -394,6 +389,29 @@ namespace Bit.App.Services catch(SQLite.SQLiteException) { } } + private void SyncOrgKeys(ProfileResponse profile) + { + var orgKeysDict = new Dictionary(); + + if(profile.Organizations != null) + { + foreach(var org in profile.Organizations) + { + try + { + var decBytes = _cryptoService.RsaDecryptToBytes(new CipherString(org.Key), null); + orgKeysDict.Add(org.Id, new CryptoKey(decBytes)); + } + catch + { + Debug.WriteLine($"Cannot set org key {org.Id}. Decryption failed."); + } + } + } + + _cryptoService.OrgKeys = orgKeysDict; + } + private void SyncStarted() { if(Application.Current == null) @@ -415,5 +433,23 @@ namespace Bit.App.Services SyncInProgress = false; MessagingCenter.Send(Application.Current, "SyncCompleted", successfully); } + + private bool CheckSuccess(ApiResult result) + { + if(!result.Succeeded) + { + SyncCompleted(false); + + if(Application.Current != null && (result.StatusCode == System.Net.HttpStatusCode.Forbidden + || result.StatusCode == System.Net.HttpStatusCode.Unauthorized)) + { + MessagingCenter.Send(Application.Current, "Logout", (string)null); + } + + return false; + } + + return true; + } } } diff --git a/src/iOS/Resources/LaunchScreen.storyboard b/src/iOS/Resources/LaunchScreen.storyboard deleted file mode 100644 index a639c2f1a..000000000 --- a/src/iOS/Resources/LaunchScreen.storyboard +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/iOS/iOS.csproj b/src/iOS/iOS.csproj index f56ec66fd..ceb39b0e5 100644 --- a/src/iOS/iOS.csproj +++ b/src/iOS/iOS.csproj @@ -253,7 +253,6 @@ -