1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-05 10:03:26 +00:00

add collection syncing

This commit is contained in:
Kyle Spearrin
2017-11-24 16:11:40 -05:00
parent 3b44ede67e
commit c9ceb09906
19 changed files with 302 additions and 21 deletions

View File

@@ -17,7 +17,9 @@ namespace Bit.App.Services
public void CreateTables()
{
_connection.CreateTable<FolderData>();
_connection.CreateTable<CollectionData>();
_connection.CreateTable<CipherData>();
_connection.CreateTable<CipherCollectionData>();
_connection.CreateTable<AttachmentData>();
_connection.CreateTable<SettingsData>();
}

View File

@@ -20,6 +20,8 @@ namespace Bit.App.Services
private readonly ISettingsApiRepository _settingsApiRepository;
private readonly ISyncApiRepository _syncApiRepository;
private readonly IFolderRepository _folderRepository;
private readonly ICollectionRepository _collectionRepository;
private readonly ICipherCollectionRepository _cipherCollectionRepository;
private readonly ICipherService _cipherService;
private readonly IAttachmentRepository _attachmentRepository;
private readonly ISettingsRepository _settingsRepository;
@@ -35,6 +37,8 @@ namespace Bit.App.Services
ISettingsApiRepository settingsApiRepository,
ISyncApiRepository syncApiRepository,
IFolderRepository folderRepository,
ICollectionRepository collectionRepository,
ICipherCollectionRepository cipherCollectionRepository,
ICipherService cipherService,
IAttachmentRepository attachmentRepository,
ISettingsRepository settingsRepository,
@@ -49,6 +53,8 @@ namespace Bit.App.Services
_settingsApiRepository = settingsApiRepository;
_syncApiRepository = syncApiRepository;
_folderRepository = folderRepository;
_collectionRepository = collectionRepository;
_cipherCollectionRepository = cipherCollectionRepository;
_cipherService = cipherService;
_attachmentRepository = attachmentRepository;
_settingsRepository = settingsRepository;
@@ -258,9 +264,9 @@ namespace Bit.App.Services
var now = DateTime.UtcNow;
var syncResponse = await _syncApiRepository.Get();
if(!CheckSuccess(syncResponse,
if(!CheckSuccess(syncResponse,
!string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
syncResponse.Result?.Profile != null &&
syncResponse.Result?.Profile != null &&
_appSettingsService.SecurityStamp != syncResponse.Result.Profile.SecurityStamp))
{
return false;
@@ -268,15 +274,17 @@ namespace Bit.App.Services
var ciphersDict = syncResponse.Result.Ciphers.ToDictionary(s => s.Id);
var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
var collectionsDict = syncResponse.Result.Collections?.ToDictionary(c => c.Id);
var cipherTask = SyncCiphersAsync(ciphersDict);
var folderTask = SyncFoldersAsync(foldersDict);
var collectionsTask = SyncCollectionsAsync(collectionsDict);
var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile);
await Task.WhenAll(cipherTask, folderTask, domainsTask, profileTask).ConfigureAwait(false);
await Task.WhenAll(cipherTask, folderTask, collectionsTask, domainsTask, profileTask).ConfigureAwait(false);
if(folderTask.Exception != null || cipherTask.Exception != null || domainsTask.Exception != null ||
profileTask.Exception != null)
if(folderTask.Exception != null || cipherTask.Exception != null || collectionsTask.Exception != null ||
domainsTask.Exception != null || profileTask.Exception != null)
{
SyncCompleted(false);
return false;
@@ -349,7 +357,48 @@ namespace Bit.App.Services
}
}
private async Task SyncCiphersAsync(IDictionary<string, CipherResponse> serviceCiphers)
private async Task SyncCollectionsAsync(IDictionary<string, CollectionResponse> serverCollections)
{
if(!_authService.IsAuthenticated)
{
return;
}
var localCollections = (await _collectionRepository.GetAllByUserIdAsync(_authService.UserId)
.ConfigureAwait(false))
.GroupBy(f => f.Id)
.Select(f => f.First())
.ToDictionary(f => f.Id);
if(serverCollections != null)
{
foreach(var serverCollection in serverCollections)
{
if(!_authService.IsAuthenticated)
{
return;
}
try
{
var data = new CollectionData(serverCollection.Value, _authService.UserId);
await _collectionRepository.UpsertAsync(data).ConfigureAwait(false);
}
catch(SQLite.SQLiteException) { }
}
}
foreach(var collection in localCollections.Where(lc => !serverCollections.ContainsKey(lc.Key)))
{
try
{
await _collectionRepository.DeleteAsync(collection.Value.Id).ConfigureAwait(false);
}
catch(SQLite.SQLiteException) { }
}
}
private async Task SyncCiphersAsync(IDictionary<string, CipherResponse> serverCiphers)
{
if(!_authService.IsAuthenticated)
{
@@ -367,16 +416,29 @@ namespace Bit.App.Services
.GroupBy(a => a.LoginId)
.ToDictionary(g => g.Key);
foreach(var serverCipher in serviceCiphers)
var cipherCollections = new List<CipherCollectionData>();
foreach(var serverCipher in serverCiphers)
{
if(!_authService.IsAuthenticated)
{
return;
}
var collectionForThisCipher = serverCipher.Value.CollectionIds?.Select(cid => new CipherCollectionData
{
CipherId = serverCipher.Value.Id,
CollectionId = cid,
UserId = _authService.UserId
}).ToList();
if(collectionForThisCipher != null && collectionForThisCipher.Any())
{
cipherCollections.AddRange(collectionForThisCipher);
}
try
{
var localCipher = localCiphers.ContainsKey(serverCipher.Value.Id) ?
var localCipher = localCiphers.ContainsKey(serverCipher.Value.Id) ?
localCiphers[serverCipher.Value.Id] : null;
var data = new CipherData(serverCipher.Value, _authService.UserId);
@@ -404,7 +466,7 @@ namespace Bit.App.Services
catch(SQLite.SQLiteException) { }
}
foreach(var cipher in localCiphers.Where(local => !serviceCiphers.ContainsKey(local.Key)))
foreach(var cipher in localCiphers.Where(local => !serverCiphers.ContainsKey(local.Key)))
{
try
{
@@ -412,6 +474,21 @@ namespace Bit.App.Services
}
catch(SQLite.SQLiteException) { }
}
try
{
await _cipherCollectionRepository.DeleteByUserIdAsync(_authService.UserId).ConfigureAwait(false);
}
catch(SQLite.SQLiteException) { }
foreach(var cipherCollection in cipherCollections)
{
try
{
await _cipherCollectionRepository.InsertAsync(cipherCollection).ConfigureAwait(false);
}
catch(SQLite.SQLiteException) { }
}
}
private async Task SyncDomainsAsync(DomainsResponse serverDomains)