diff --git a/src/App/Abstractions/Services/IAuthService.cs b/src/App/Abstractions/Services/IAuthService.cs index 21f321831..ebaf71c5a 100644 --- a/src/App/Abstractions/Services/IAuthService.cs +++ b/src/App/Abstractions/Services/IAuthService.cs @@ -12,6 +12,7 @@ namespace Bit.App.Abstractions string Email { get; set; } string PIN { get; set; } + bool BelongsToOrganization(string orgId); void LogOut(); Task TokenPostAsync(string email, string masterPassword); Task TokenPostTwoFactorAsync(string token, string email, string masterPasswordHash, CryptoKey key); diff --git a/src/App/Abstractions/Services/ISyncService.cs b/src/App/Abstractions/Services/ISyncService.cs index fb0fdfc26..1e0b5bd64 100644 --- a/src/App/Abstractions/Services/ISyncService.cs +++ b/src/App/Abstractions/Services/ISyncService.cs @@ -7,8 +7,10 @@ namespace Bit.App.Abstractions { bool SyncInProgress { get; } Task SyncCipherAsync(string id); + Task SyncFolderAsync(string id); Task SyncDeleteFolderAsync(string id, DateTime revisionDate); Task SyncDeleteLoginAsync(string id); + Task SyncSettingsAsync(); Task FullSyncAsync(bool forceSync = false); Task FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false); } diff --git a/src/App/Enums/PushType.cs b/src/App/Enums/PushType.cs index 9f4a8e3c0..6a697dba7 100644 --- a/src/App/Enums/PushType.cs +++ b/src/App/Enums/PushType.cs @@ -6,6 +6,13 @@ SyncCipherCreate = 1, SyncLoginDelete = 2, SyncFolderDelete = 3, - SyncCiphers = 4 + SyncCiphers = 4, + + SyncVault = 5, + SyncOrgKeys = 6, + SyncFolderCreate = 7, + SyncFolderUpdate = 8, + SyncCipherDelete = 9, + SyncSettings = 10 } } diff --git a/src/App/Models/PushNotification.cs b/src/App/Models/PushNotification.cs index 129e45432..e81221dd2 100644 --- a/src/App/Models/PushNotification.cs +++ b/src/App/Models/PushNotification.cs @@ -8,19 +8,24 @@ namespace Bit.App.Models public PushType Type { get; set; } } - public abstract class SyncPushNotification : PushNotification - { - public string UserId { get; set; } - } - - public class SyncCipherPushNotification : SyncPushNotification + public class SyncCipherPushNotification : PushNotification { public string Id { get; set; } + public string UserId { get; set; } + public string OrganizationId { get; set; } public DateTime RevisionDate { get; set; } } - public class SyncCiphersPushNotification : SyncPushNotification + public class SyncFolderPushNotification : PushNotification { + public string Id { get; set; } + public string UserId { get; set; } + public DateTime RevisionDate { get; set; } + } + + public class SyncUserPushNotification : PushNotification + { + public string UserId { get; set; } public DateTime Date { get; set; } } } diff --git a/src/App/Services/AuthService.cs b/src/App/Services/AuthService.cs index 68f1d8a0b..79176ba7e 100644 --- a/src/App/Services/AuthService.cs +++ b/src/App/Services/AuthService.cs @@ -191,6 +191,11 @@ namespace Bit.App.Services } } + public bool BelongsToOrganization(string orgId) + { + return !string.IsNullOrWhiteSpace(orgId) && (_cryptoService.OrgKeys?.ContainsKey(orgId) ?? false); + } + public void LogOut() { _tokenService.Token = null; diff --git a/src/App/Services/PushNotificationListener.cs b/src/App/Services/PushNotificationListener.cs index 9d6c3112d..eacb37575 100644 --- a/src/App/Services/PushNotificationListener.cs +++ b/src/App/Services/PushNotificationListener.cs @@ -59,15 +59,28 @@ namespace Bit.App.Services { case Enums.PushType.SyncCipherUpdate: case Enums.PushType.SyncCipherCreate: - var createUpdateMessage = values.ToObject(); - if(createUpdateMessage.UserId != _authService.UserId) + var cipherCreateUpdateMessage = values.ToObject(); + if(cipherCreateUpdateMessage.UserId != null && cipherCreateUpdateMessage.UserId != _authService.UserId) { break; } - _syncService.SyncCipherAsync(createUpdateMessage.Id); + else if(!_authService.BelongsToOrganization(cipherCreateUpdateMessage.OrganizationId)) + { + break; + } + _syncService.SyncCipherAsync(cipherCreateUpdateMessage.Id); + break; + case Enums.PushType.SyncFolderUpdate: + case Enums.PushType.SyncFolderCreate: + var folderCreateUpdateMessage = values.ToObject(); + if(folderCreateUpdateMessage.UserId != _authService.UserId) + { + break; + } + _syncService.SyncFolderAsync(folderCreateUpdateMessage.Id); break; case Enums.PushType.SyncFolderDelete: - var folderDeleteMessage = values.ToObject(); + var folderDeleteMessage = values.ToObject(); if(folderDeleteMessage.UserId != _authService.UserId) { break; @@ -76,20 +89,33 @@ namespace Bit.App.Services break; case Enums.PushType.SyncLoginDelete: var loginDeleteMessage = values.ToObject(); - if(loginDeleteMessage.UserId != _authService.UserId) + if(loginDeleteMessage.UserId != null && loginDeleteMessage.UserId != _authService.UserId) + { + break; + } + else if(!_authService.BelongsToOrganization(loginDeleteMessage.OrganizationId)) { break; } _syncService.SyncDeleteLoginAsync(loginDeleteMessage.Id); break; case Enums.PushType.SyncCiphers: - var cipherMessage = values.ToObject(); + case Enums.PushType.SyncVault: + var cipherMessage = values.ToObject(); if(cipherMessage.UserId != _authService.UserId) { break; } _syncService.FullSyncAsync(true); break; + case Enums.PushType.SyncSettings: + var domainMessage = values.ToObject(); + if(domainMessage.UserId != _authService.UserId) + { + break; + } + _syncService.SyncSettingsAsync(); + break; default: break; } diff --git a/src/App/Services/SyncService.cs b/src/App/Services/SyncService.cs index 202906ce3..9025e70ad 100644 --- a/src/App/Services/SyncService.cs +++ b/src/App/Services/SyncService.cs @@ -96,6 +96,44 @@ namespace Bit.App.Services return true; } + public async Task SyncFolderAsync(string id) + { + if(!_authService.IsAuthenticated) + { + return false; + } + + SyncStarted(); + + var folder = await _folderApiRepository.GetByIdAsync(id).ConfigureAwait(false); + if(!folder.Succeeded) + { + 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; + } + + try + { + var folderData = new FolderData(folder.Result, _authService.UserId); + await _folderRepository.UpsertAsync(folderData).ConfigureAwait(false); + } + catch(SQLite.SQLiteException) + { + SyncCompleted(false); + return false; + } + + SyncCompleted(true); + return true; + } + public async Task SyncDeleteFolderAsync(string id, DateTime revisionDate) { if(!_authService.IsAuthenticated) @@ -140,6 +178,35 @@ namespace Bit.App.Services } } + public async Task SyncSettingsAsync() + { + if(!_authService.IsAuthenticated) + { + return false; + } + + SyncStarted(); + + var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false); + if(!domains.Succeeded) + { + 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; + } + + await SyncDomainsAsync(domains.Result); + + SyncCompleted(true); + return true; + } + public async Task FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false) { DateTime? lastSync = _settings.GetValueOrDefault(Constants.LastSync, null);