mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-04 08:50:18 +01:00
add collection syncing
This commit is contained in:
parent
3b44ede67e
commit
c9ceb09906
@ -226,6 +226,8 @@ namespace Bit.Android
|
|||||||
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
|
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
|
||||||
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
|
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
|
||||||
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
|
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
|
||||||
|
container.RegisterSingleton<ICollectionRepository, CollectionRepository>();
|
||||||
|
container.RegisterSingleton<ICipherCollectionRepository, CipherCollectionRepository>();
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
container.RegisterSingleton(CrossSettings.Current);
|
container.RegisterSingleton(CrossSettings.Current);
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ICipherCollectionRepository
|
||||||
|
{
|
||||||
|
Task<IEnumerable<CipherCollectionData>> GetAllByUserIdAsync(string userId);
|
||||||
|
Task InsertAsync(CipherCollectionData obj);
|
||||||
|
Task DeleteAsync(CipherCollectionData obj);
|
||||||
|
Task DeleteByUserIdAsync(string userId);
|
||||||
|
}
|
||||||
|
}
|
11
src/App/Abstractions/Repositories/ICollectionRepository.cs
Normal file
11
src/App/Abstractions/Repositories/ICollectionRepository.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ICollectionRepository : IRepository<CollectionData, string>
|
||||||
|
{
|
||||||
|
Task<IEnumerable<CollectionData>> GetAllByUserIdAsync(string userId);
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" />
|
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" />
|
||||||
|
<Compile Include="Abstractions\Repositories\ICipherCollectionRepository.cs" />
|
||||||
|
<Compile Include="Abstractions\Repositories\ICollectionRepository.cs" />
|
||||||
<Compile Include="Abstractions\Repositories\ISyncApiRepository.cs" />
|
<Compile Include="Abstractions\Repositories\ISyncApiRepository.cs" />
|
||||||
<Compile Include="Abstractions\Repositories\ITwoFactorApiRepository.cs" />
|
<Compile Include="Abstractions\Repositories\ITwoFactorApiRepository.cs" />
|
||||||
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
|
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
|
||||||
@ -107,6 +109,7 @@
|
|||||||
<Compile Include="Models\Api\FieldDataModel.cs" />
|
<Compile Include="Models\Api\FieldDataModel.cs" />
|
||||||
<Compile Include="Models\Api\CardDataModel.cs" />
|
<Compile Include="Models\Api\CardDataModel.cs" />
|
||||||
<Compile Include="Models\Api\IdentityDataModel.cs" />
|
<Compile Include="Models\Api\IdentityDataModel.cs" />
|
||||||
|
<Compile Include="Models\Api\Response\CollectionResponse.cs" />
|
||||||
<Compile Include="Models\Api\SecureNoteDataModel.cs" />
|
<Compile Include="Models\Api\SecureNoteDataModel.cs" />
|
||||||
<Compile Include="Models\Api\Request\DeviceTokenRequest.cs" />
|
<Compile Include="Models\Api\Request\DeviceTokenRequest.cs" />
|
||||||
<Compile Include="Models\Api\Request\FolderRequest.cs" />
|
<Compile Include="Models\Api\Request\FolderRequest.cs" />
|
||||||
@ -134,7 +137,10 @@
|
|||||||
<Compile Include="Models\CipherString.cs" />
|
<Compile Include="Models\CipherString.cs" />
|
||||||
<Compile Include="Models\Data\AttachmentData.cs" />
|
<Compile Include="Models\Data\AttachmentData.cs" />
|
||||||
<Compile Include="Models\Attachment.cs" />
|
<Compile Include="Models\Attachment.cs" />
|
||||||
|
<Compile Include="Models\Data\CipherCollectionData.cs" />
|
||||||
|
<Compile Include="Models\Data\CollectionData.cs" />
|
||||||
<Compile Include="Models\Field.cs" />
|
<Compile Include="Models\Field.cs" />
|
||||||
|
<Compile Include="Models\Collection.cs" />
|
||||||
<Compile Include="Models\Identity.cs" />
|
<Compile Include="Models\Identity.cs" />
|
||||||
<Compile Include="Models\Login.cs" />
|
<Compile Include="Models\Login.cs" />
|
||||||
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
|
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
|
||||||
@ -186,6 +192,9 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Abstractions\Repositories\ICipherRepository.cs" />
|
<Compile Include="Abstractions\Repositories\ICipherRepository.cs" />
|
||||||
<Compile Include="Repositories\AttachmentRepository.cs" />
|
<Compile Include="Repositories\AttachmentRepository.cs" />
|
||||||
|
<Compile Include="Repositories\BaseRepository.cs" />
|
||||||
|
<Compile Include="Repositories\CipherCollectionRepository.cs" />
|
||||||
|
<Compile Include="Repositories\CollectionRepository.cs" />
|
||||||
<Compile Include="Repositories\SyncApiRepository.cs" />
|
<Compile Include="Repositories\SyncApiRepository.cs" />
|
||||||
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
|
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
|
||||||
<Compile Include="Repositories\SettingsApiRepository.cs" />
|
<Compile Include="Repositories\SettingsApiRepository.cs" />
|
||||||
|
@ -17,6 +17,7 @@ namespace Bit.App.Models.Api
|
|||||||
public bool OrganizationUseTotp { get; set; }
|
public bool OrganizationUseTotp { get; set; }
|
||||||
public JObject Data { get; set; }
|
public JObject Data { get; set; }
|
||||||
public IEnumerable<AttachmentResponse> Attachments { get; set; }
|
public IEnumerable<AttachmentResponse> Attachments { get; set; }
|
||||||
|
public IEnumerable<string> CollectionIds { get; set; }
|
||||||
public DateTime RevisionDate { get; set; }
|
public DateTime RevisionDate { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
src/App/Models/Api/Response/CollectionResponse.cs
Normal file
9
src/App/Models/Api/Response/CollectionResponse.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class CollectionResponse
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string OrganizationId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ namespace Bit.App.Models.Api
|
|||||||
{
|
{
|
||||||
public ProfileResponse Profile { get; set; }
|
public ProfileResponse Profile { get; set; }
|
||||||
public IEnumerable<FolderResponse> Folders { get; set; }
|
public IEnumerable<FolderResponse> Folders { get; set; }
|
||||||
|
public IEnumerable<CollectionResponse> Collections { get; set; }
|
||||||
public IEnumerable<CipherResponse> Ciphers { get; set; }
|
public IEnumerable<CipherResponse> Ciphers { get; set; }
|
||||||
public DomainsResponse Domains { get; set; }
|
public DomainsResponse Domains { get; set; }
|
||||||
}
|
}
|
||||||
|
29
src/App/Models/Collection.cs
Normal file
29
src/App/Models/Collection.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using Bit.App.Models.Data;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class Collection
|
||||||
|
{
|
||||||
|
public Collection()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Collection(CollectionData data)
|
||||||
|
{
|
||||||
|
Id = data.Id;
|
||||||
|
OrganizationId = data.OrganizationId;
|
||||||
|
Name = data.Name != null ? new CipherString(data.Name) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection(CollectionResponse response)
|
||||||
|
{
|
||||||
|
Id = response.Id;
|
||||||
|
OrganizationId = response.OrganizationId;
|
||||||
|
Name = response.Name != null ? new CipherString(response.Name) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string OrganizationId { get; set; }
|
||||||
|
public CipherString Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
18
src/App/Models/Data/CipherCollectionData.cs
Normal file
18
src/App/Models/Data/CipherCollectionData.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Data
|
||||||
|
{
|
||||||
|
[Table("CipherCollection")]
|
||||||
|
public class CipherCollectionData
|
||||||
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
[AutoIncrement]
|
||||||
|
public int Id { get; set; }
|
||||||
|
[Indexed]
|
||||||
|
public string UserId { get; set; }
|
||||||
|
[Indexed]
|
||||||
|
public string CipherId { get; set; }
|
||||||
|
[Indexed]
|
||||||
|
public string CollectionId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
36
src/App/Models/Data/CollectionData.cs
Normal file
36
src/App/Models/Data/CollectionData.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using SQLite;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Data
|
||||||
|
{
|
||||||
|
[Table("Collection")]
|
||||||
|
public class CollectionData : IDataObject<string>
|
||||||
|
{
|
||||||
|
public CollectionData()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public CollectionData(Collection collection, string userId)
|
||||||
|
{
|
||||||
|
Id = collection.Id;
|
||||||
|
UserId = userId;
|
||||||
|
Name = collection.Name?.EncryptedString;
|
||||||
|
OrganizationId = collection.OrganizationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionData(CollectionResponse collection, string userId)
|
||||||
|
{
|
||||||
|
Id = collection.Id;
|
||||||
|
UserId = userId;
|
||||||
|
Name = collection.Name;
|
||||||
|
OrganizationId = collection.OrganizationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrimaryKey]
|
||||||
|
public string Id { get; set; }
|
||||||
|
[Indexed]
|
||||||
|
public string UserId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string OrganizationId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -32,10 +32,5 @@ namespace Bit.App.Models.Data
|
|||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
public Folder ToFolder()
|
|
||||||
{
|
|
||||||
return new Folder(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/App/Repositories/BaseRepository.cs
Normal file
15
src/App/Repositories/BaseRepository.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using Bit.App.Abstractions;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Bit.App.Repositories
|
||||||
|
{
|
||||||
|
public abstract class BaseRepository
|
||||||
|
{
|
||||||
|
public BaseRepository(ISqlService sqlService)
|
||||||
|
{
|
||||||
|
Connection = sqlService.GetConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SQLiteConnection Connection { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
40
src/App/Repositories/CipherCollectionRepository.cs
Normal file
40
src/App/Repositories/CipherCollectionRepository.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Bit.App.Repositories
|
||||||
|
{
|
||||||
|
public class CipherCollectionRepository : BaseRepository, ICipherCollectionRepository
|
||||||
|
{
|
||||||
|
public CipherCollectionRepository(ISqlService sqlService)
|
||||||
|
: base(sqlService)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Task<IEnumerable<CipherCollectionData>> GetAllByUserIdAsync(string userId)
|
||||||
|
{
|
||||||
|
var cipherCollections = Connection.Table<CipherCollectionData>().Where(f => f.UserId == userId)
|
||||||
|
.Cast<CipherCollectionData>();
|
||||||
|
return Task.FromResult(cipherCollections);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task InsertAsync(CipherCollectionData obj)
|
||||||
|
{
|
||||||
|
Connection.Insert(obj);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task DeleteAsync(CipherCollectionData obj)
|
||||||
|
{
|
||||||
|
Connection.Delete<CipherCollectionData>(obj.Id);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task DeleteByUserIdAsync(string userId)
|
||||||
|
{
|
||||||
|
Connection.Execute("DELETE FROM CipherCollection WHERE UserId = ?", userId);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/App/Repositories/CollectionRepository.cs
Normal file
21
src/App/Repositories/CollectionRepository.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.App.Repositories
|
||||||
|
{
|
||||||
|
public class CollectionRepository : Repository<CollectionData, string>, ICollectionRepository
|
||||||
|
{
|
||||||
|
public CollectionRepository(ISqlService sqlService)
|
||||||
|
: base(sqlService)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Task<IEnumerable<CollectionData>> GetAllByUserIdAsync(string userId)
|
||||||
|
{
|
||||||
|
var folders = Connection.Table<CollectionData>().Where(f => f.UserId == userId).Cast<CollectionData>();
|
||||||
|
return Task.FromResult(folders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,20 +3,16 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
public abstract class Repository<T, TId> : IRepository<T, TId>
|
public abstract class Repository<T, TId> : BaseRepository, IRepository<T, TId>
|
||||||
where TId : IEquatable<TId>
|
where TId : IEquatable<TId>
|
||||||
where T : class, IDataObject<TId>, new()
|
where T : class, IDataObject<TId>, new()
|
||||||
{
|
{
|
||||||
public Repository(ISqlService sqlService)
|
public Repository(ISqlService sqlService)
|
||||||
{
|
: base(sqlService)
|
||||||
Connection = sqlService.GetConnection();
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
protected SQLiteConnection Connection { get; private set; }
|
|
||||||
|
|
||||||
public virtual Task<T> GetByIdAsync(TId id)
|
public virtual Task<T> GetByIdAsync(TId id)
|
||||||
{
|
{
|
||||||
@ -39,6 +35,7 @@ namespace Bit.App.Repositories
|
|||||||
Connection.Update(obj);
|
Connection.Update(obj);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task UpsertAsync(T obj)
|
public virtual Task UpsertAsync(T obj)
|
||||||
{
|
{
|
||||||
Connection.InsertOrReplace(obj);
|
Connection.InsertOrReplace(obj);
|
||||||
|
@ -17,7 +17,9 @@ namespace Bit.App.Services
|
|||||||
public void CreateTables()
|
public void CreateTables()
|
||||||
{
|
{
|
||||||
_connection.CreateTable<FolderData>();
|
_connection.CreateTable<FolderData>();
|
||||||
|
_connection.CreateTable<CollectionData>();
|
||||||
_connection.CreateTable<CipherData>();
|
_connection.CreateTable<CipherData>();
|
||||||
|
_connection.CreateTable<CipherCollectionData>();
|
||||||
_connection.CreateTable<AttachmentData>();
|
_connection.CreateTable<AttachmentData>();
|
||||||
_connection.CreateTable<SettingsData>();
|
_connection.CreateTable<SettingsData>();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ namespace Bit.App.Services
|
|||||||
private readonly ISettingsApiRepository _settingsApiRepository;
|
private readonly ISettingsApiRepository _settingsApiRepository;
|
||||||
private readonly ISyncApiRepository _syncApiRepository;
|
private readonly ISyncApiRepository _syncApiRepository;
|
||||||
private readonly IFolderRepository _folderRepository;
|
private readonly IFolderRepository _folderRepository;
|
||||||
|
private readonly ICollectionRepository _collectionRepository;
|
||||||
|
private readonly ICipherCollectionRepository _cipherCollectionRepository;
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IAttachmentRepository _attachmentRepository;
|
private readonly IAttachmentRepository _attachmentRepository;
|
||||||
private readonly ISettingsRepository _settingsRepository;
|
private readonly ISettingsRepository _settingsRepository;
|
||||||
@ -35,6 +37,8 @@ namespace Bit.App.Services
|
|||||||
ISettingsApiRepository settingsApiRepository,
|
ISettingsApiRepository settingsApiRepository,
|
||||||
ISyncApiRepository syncApiRepository,
|
ISyncApiRepository syncApiRepository,
|
||||||
IFolderRepository folderRepository,
|
IFolderRepository folderRepository,
|
||||||
|
ICollectionRepository collectionRepository,
|
||||||
|
ICipherCollectionRepository cipherCollectionRepository,
|
||||||
ICipherService cipherService,
|
ICipherService cipherService,
|
||||||
IAttachmentRepository attachmentRepository,
|
IAttachmentRepository attachmentRepository,
|
||||||
ISettingsRepository settingsRepository,
|
ISettingsRepository settingsRepository,
|
||||||
@ -49,6 +53,8 @@ namespace Bit.App.Services
|
|||||||
_settingsApiRepository = settingsApiRepository;
|
_settingsApiRepository = settingsApiRepository;
|
||||||
_syncApiRepository = syncApiRepository;
|
_syncApiRepository = syncApiRepository;
|
||||||
_folderRepository = folderRepository;
|
_folderRepository = folderRepository;
|
||||||
|
_collectionRepository = collectionRepository;
|
||||||
|
_cipherCollectionRepository = cipherCollectionRepository;
|
||||||
_cipherService = cipherService;
|
_cipherService = cipherService;
|
||||||
_attachmentRepository = attachmentRepository;
|
_attachmentRepository = attachmentRepository;
|
||||||
_settingsRepository = settingsRepository;
|
_settingsRepository = settingsRepository;
|
||||||
@ -258,9 +264,9 @@ namespace Bit.App.Services
|
|||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
var syncResponse = await _syncApiRepository.Get();
|
var syncResponse = await _syncApiRepository.Get();
|
||||||
if(!CheckSuccess(syncResponse,
|
if(!CheckSuccess(syncResponse,
|
||||||
!string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
|
!string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
|
||||||
syncResponse.Result?.Profile != null &&
|
syncResponse.Result?.Profile != null &&
|
||||||
_appSettingsService.SecurityStamp != syncResponse.Result.Profile.SecurityStamp))
|
_appSettingsService.SecurityStamp != syncResponse.Result.Profile.SecurityStamp))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -268,15 +274,17 @@ namespace Bit.App.Services
|
|||||||
|
|
||||||
var ciphersDict = syncResponse.Result.Ciphers.ToDictionary(s => s.Id);
|
var ciphersDict = syncResponse.Result.Ciphers.ToDictionary(s => s.Id);
|
||||||
var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
|
var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
|
||||||
|
var collectionsDict = syncResponse.Result.Collections?.ToDictionary(c => c.Id);
|
||||||
|
|
||||||
var cipherTask = SyncCiphersAsync(ciphersDict);
|
var cipherTask = SyncCiphersAsync(ciphersDict);
|
||||||
var folderTask = SyncFoldersAsync(foldersDict);
|
var folderTask = SyncFoldersAsync(foldersDict);
|
||||||
|
var collectionsTask = SyncCollectionsAsync(collectionsDict);
|
||||||
var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
|
var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
|
||||||
var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile);
|
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 ||
|
if(folderTask.Exception != null || cipherTask.Exception != null || collectionsTask.Exception != null ||
|
||||||
profileTask.Exception != null)
|
domainsTask.Exception != null || profileTask.Exception != null)
|
||||||
{
|
{
|
||||||
SyncCompleted(false);
|
SyncCompleted(false);
|
||||||
return 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)
|
if(!_authService.IsAuthenticated)
|
||||||
{
|
{
|
||||||
@ -367,16 +416,29 @@ namespace Bit.App.Services
|
|||||||
.GroupBy(a => a.LoginId)
|
.GroupBy(a => a.LoginId)
|
||||||
.ToDictionary(g => g.Key);
|
.ToDictionary(g => g.Key);
|
||||||
|
|
||||||
foreach(var serverCipher in serviceCiphers)
|
var cipherCollections = new List<CipherCollectionData>();
|
||||||
|
foreach(var serverCipher in serverCiphers)
|
||||||
{
|
{
|
||||||
if(!_authService.IsAuthenticated)
|
if(!_authService.IsAuthenticated)
|
||||||
{
|
{
|
||||||
return;
|
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
|
try
|
||||||
{
|
{
|
||||||
var localCipher = localCiphers.ContainsKey(serverCipher.Value.Id) ?
|
var localCipher = localCiphers.ContainsKey(serverCipher.Value.Id) ?
|
||||||
localCiphers[serverCipher.Value.Id] : null;
|
localCiphers[serverCipher.Value.Id] : null;
|
||||||
|
|
||||||
var data = new CipherData(serverCipher.Value, _authService.UserId);
|
var data = new CipherData(serverCipher.Value, _authService.UserId);
|
||||||
@ -404,7 +466,7 @@ namespace Bit.App.Services
|
|||||||
catch(SQLite.SQLiteException) { }
|
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
|
try
|
||||||
{
|
{
|
||||||
@ -412,6 +474,21 @@ namespace Bit.App.Services
|
|||||||
}
|
}
|
||||||
catch(SQLite.SQLiteException) { }
|
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)
|
private async Task SyncDomainsAsync(DomainsResponse serverDomains)
|
||||||
|
@ -301,6 +301,8 @@ namespace Bit.iOS.Extension
|
|||||||
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
|
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
|
||||||
container.RegisterSingleton<ICipherApiRepository, CipherApiRepository>();
|
container.RegisterSingleton<ICipherApiRepository, CipherApiRepository>();
|
||||||
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
|
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
|
||||||
|
container.RegisterSingleton<ICollectionRepository, CollectionRepository>();
|
||||||
|
container.RegisterSingleton<ICipherCollectionRepository, CipherCollectionRepository>();
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
container.RegisterSingleton(CrossConnectivity.Current);
|
container.RegisterSingleton(CrossConnectivity.Current);
|
||||||
|
@ -285,6 +285,8 @@ namespace Bit.iOS
|
|||||||
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
|
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
|
||||||
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
|
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
|
||||||
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
|
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
|
||||||
|
container.RegisterSingleton<ICollectionRepository, CollectionRepository>();
|
||||||
|
container.RegisterSingleton<ICipherCollectionRepository, CipherCollectionRepository>();
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
container.RegisterSingleton(CrossConnectivity.Current);
|
container.RegisterSingleton(CrossConnectivity.Current);
|
||||||
|
Loading…
Reference in New Issue
Block a user