change syncing to use new sync api

This commit is contained in:
Kyle Spearrin 2017-09-20 13:17:05 -04:00
parent 45d171e0e3
commit a426d98e92
10 changed files with 114 additions and 60 deletions

View file

@ -228,6 +228,7 @@ namespace Bit.Android
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossSettings.Current);

View file

@ -10,6 +10,5 @@ namespace Bit.App.Abstractions
Task<ApiResult> PostPasswordHintAsync(PasswordHintRequest requestObj);
Task<ApiResult<DateTime?>> GetAccountRevisionDateAsync();
Task<ApiResult<ProfileResponse>> GetProfileAsync();
Task<ApiResult<KeysResponse>> GetKeys();
}
}

View file

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ISyncApiRepository
{
Task<ApiResult<SyncResponse>> Get();
}
}

View file

@ -36,6 +36,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" />
<Compile Include="Abstractions\Repositories\ISyncApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ITwoFactorApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" />
@ -116,6 +117,7 @@
<Compile Include="Models\Api\Response\LoginResponse.cs" />
<Compile Include="Models\Api\Response\ProfileOrganizationResponse.cs" />
<Compile Include="Models\Api\Response\KeysResponse.cs" />
<Compile Include="Models\Api\Response\SyncResponse.cs" />
<Compile Include="Models\Api\Response\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" />
@ -169,6 +171,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
<Compile Include="Repositories\AttachmentRepository.cs" />
<Compile Include="Repositories\SyncApiRepository.cs" />
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
<Compile Include="Repositories\SettingsApiRepository.cs" />
<Compile Include="Repositories\ApiRepository.cs" />

View file

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public class SyncResponse
{
public ProfileResponse Profile { get; set; }
public IEnumerable<FolderResponse> Folders { get; set; }
public IEnumerable<CipherResponse> Ciphers { get; set; }
public DomainsResponse Domains { get; set; }
}
}

View file

@ -172,45 +172,5 @@ namespace Bit.App.Repositories
}
}
}
public virtual async Task<ApiResult<KeysResponse>> GetKeys()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<KeysResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<KeysResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/keys")),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<KeysResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<KeysResponse>(responseContent);
return ApiResult<KeysResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<KeysResponse>();
}
}
}
}
}

View file

@ -0,0 +1,63 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Plugin.Connectivity.Abstractions;
using Newtonsoft.Json;
namespace Bit.App.Repositories
{
public class SyncApiRepository : BaseApiRepository, ISyncApiRepository
{
public SyncApiRepository(
IConnectivity connectivity,
IHttpService httpService,
ITokenService tokenService)
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "sync";
public virtual async Task<ApiResult<SyncResponse>> Get()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<SyncResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<SyncResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(
string.Concat(client.BaseAddress, ApiRoute)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<SyncResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<SyncResponse>(responseContent);
return ApiResult<SyncResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<SyncResponse>();
}
}
}
}
}

View file

@ -16,9 +16,9 @@ namespace Bit.App.Services
{
private readonly ICipherApiRepository _cipherApiRepository;
private readonly IFolderApiRepository _folderApiRepository;
private readonly ILoginApiRepository _loginApiRepository;
private readonly IAccountsApiRepository _accountsApiRepository;
private readonly ISettingsApiRepository _settingsApiRepository;
private readonly ISyncApiRepository _syncApiRepository;
private readonly IFolderRepository _folderRepository;
private readonly ILoginRepository _loginRepository;
private readonly IAttachmentRepository _attachmentRepository;
@ -31,9 +31,9 @@ namespace Bit.App.Services
public SyncService(
ICipherApiRepository cipherApiRepository,
IFolderApiRepository folderApiRepository,
ILoginApiRepository loginApiRepository,
IAccountsApiRepository accountsApiRepository,
ISettingsApiRepository settingsApiRepository,
ISyncApiRepository syncApiRepository,
IFolderRepository folderRepository,
ILoginRepository loginRepository,
IAttachmentRepository attachmentRepository,
@ -45,9 +45,9 @@ namespace Bit.App.Services
{
_cipherApiRepository = cipherApiRepository;
_folderApiRepository = folderApiRepository;
_loginApiRepository = loginApiRepository;
_accountsApiRepository = accountsApiRepository;
_settingsApiRepository = settingsApiRepository;
_syncApiRepository = syncApiRepository;
_folderRepository = folderRepository;
_loginRepository = loginRepository;
_attachmentRepository = attachmentRepository;
@ -268,29 +268,23 @@ namespace Bit.App.Services
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, !string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
_appSettingsService.SecurityStamp != profile.Result.SecurityStamp))
var syncResponse = await _syncApiRepository.Get();
if(!CheckSuccess(syncResponse,
!string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
syncResponse.Result?.Profile != null &&
_appSettingsService.SecurityStamp != syncResponse.Result.Profile.SecurityStamp))
{
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(!CheckSuccess(ciphers) || !CheckSuccess(folders) || !CheckSuccess(domains))
{
return false;
}
var loginsDict = ciphers.Result.Data.Where(c => c.Type == Enums.CipherType.Login).ToDictionary(s => s.Id);
var foldersDict = folders.Result.Data.ToDictionary(f => f.Id);
var loginsDict = syncResponse.Result.Ciphers.Where(c => c.Type == Enums.CipherType.Login)
.ToDictionary(s => s.Id);
var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
var loginTask = SyncLoginsAsync(loginsDict);
var folderTask = SyncFoldersAsync(foldersDict);
var domainsTask = SyncDomainsAsync(domains.Result);
var profileTask = SyncProfileKeysAsync(profile.Result);
var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile);
await Task.WhenAll(loginTask, folderTask, domainsTask, profileTask).ConfigureAwait(false);
if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null ||
@ -436,6 +430,11 @@ namespace Bit.App.Services
private async Task SyncDomainsAsync(DomainsResponse serverDomains)
{
if(serverDomains == null)
{
return;
}
var eqDomains = new List<IEnumerable<string>>();
if(serverDomains.EquivalentDomains != null)
{
@ -460,6 +459,11 @@ namespace Bit.App.Services
private Task SyncProfileKeysAsync(ProfileResponse profile)
{
if(profile == null)
{
return Task.FromResult(0);
}
if(!string.IsNullOrWhiteSpace(profile.Key))
{
_cryptoService.SetEncKey(new CipherString(profile.Key));

View file

@ -299,6 +299,7 @@ namespace Bit.iOS.Extension
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
container.RegisterSingleton<ICipherApiRepository, CipherApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossConnectivity.Current);

View file

@ -285,6 +285,7 @@ namespace Bit.iOS
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossConnectivity.Current);