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<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>(); container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>(); container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other // Other
container.RegisterSingleton(CrossSettings.Current); container.RegisterSingleton(CrossSettings.Current);

View file

@ -10,6 +10,5 @@ namespace Bit.App.Abstractions
Task<ApiResult> PostPasswordHintAsync(PasswordHintRequest requestObj); Task<ApiResult> PostPasswordHintAsync(PasswordHintRequest requestObj);
Task<ApiResult<DateTime?>> GetAccountRevisionDateAsync(); Task<ApiResult<DateTime?>> GetAccountRevisionDateAsync();
Task<ApiResult<ProfileResponse>> GetProfileAsync(); 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> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" /> <Compile Include="Abstractions\Repositories\IAttachmentRepository.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" />
<Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" /> <Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" />
@ -116,6 +117,7 @@
<Compile Include="Models\Api\Response\LoginResponse.cs" /> <Compile Include="Models\Api\Response\LoginResponse.cs" />
<Compile Include="Models\Api\Response\ProfileOrganizationResponse.cs" /> <Compile Include="Models\Api\Response\ProfileOrganizationResponse.cs" />
<Compile Include="Models\Api\Response\KeysResponse.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\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" /> <Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" /> <Compile Include="Models\Api\LoginDataModel.cs" />
@ -169,6 +171,7 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" /> <Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
<Compile Include="Repositories\AttachmentRepository.cs" /> <Compile Include="Repositories\AttachmentRepository.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" />
<Compile Include="Repositories\ApiRepository.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 ICipherApiRepository _cipherApiRepository;
private readonly IFolderApiRepository _folderApiRepository; private readonly IFolderApiRepository _folderApiRepository;
private readonly ILoginApiRepository _loginApiRepository;
private readonly IAccountsApiRepository _accountsApiRepository; private readonly IAccountsApiRepository _accountsApiRepository;
private readonly ISettingsApiRepository _settingsApiRepository; private readonly ISettingsApiRepository _settingsApiRepository;
private readonly ISyncApiRepository _syncApiRepository;
private readonly IFolderRepository _folderRepository; private readonly IFolderRepository _folderRepository;
private readonly ILoginRepository _loginRepository; private readonly ILoginRepository _loginRepository;
private readonly IAttachmentRepository _attachmentRepository; private readonly IAttachmentRepository _attachmentRepository;
@ -31,9 +31,9 @@ namespace Bit.App.Services
public SyncService( public SyncService(
ICipherApiRepository cipherApiRepository, ICipherApiRepository cipherApiRepository,
IFolderApiRepository folderApiRepository, IFolderApiRepository folderApiRepository,
ILoginApiRepository loginApiRepository,
IAccountsApiRepository accountsApiRepository, IAccountsApiRepository accountsApiRepository,
ISettingsApiRepository settingsApiRepository, ISettingsApiRepository settingsApiRepository,
ISyncApiRepository syncApiRepository,
IFolderRepository folderRepository, IFolderRepository folderRepository,
ILoginRepository loginRepository, ILoginRepository loginRepository,
IAttachmentRepository attachmentRepository, IAttachmentRepository attachmentRepository,
@ -45,9 +45,9 @@ namespace Bit.App.Services
{ {
_cipherApiRepository = cipherApiRepository; _cipherApiRepository = cipherApiRepository;
_folderApiRepository = folderApiRepository; _folderApiRepository = folderApiRepository;
_loginApiRepository = loginApiRepository;
_accountsApiRepository = accountsApiRepository; _accountsApiRepository = accountsApiRepository;
_settingsApiRepository = settingsApiRepository; _settingsApiRepository = settingsApiRepository;
_syncApiRepository = syncApiRepository;
_folderRepository = folderRepository; _folderRepository = folderRepository;
_loginRepository = loginRepository; _loginRepository = loginRepository;
_attachmentRepository = attachmentRepository; _attachmentRepository = attachmentRepository;
@ -268,29 +268,23 @@ namespace Bit.App.Services
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
// Just check profile first to make sure we'll have a success with the API var syncResponse = await _syncApiRepository.Get();
var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false); if(!CheckSuccess(syncResponse,
if(!CheckSuccess(profile, !string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) && !string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
_appSettingsService.SecurityStamp != profile.Result.SecurityStamp)) syncResponse.Result?.Profile != null &&
_appSettingsService.SecurityStamp != syncResponse.Result.Profile.SecurityStamp))
{ {
return false; return false;
} }
var ciphers = await _cipherApiRepository.GetAsync().ConfigureAwait(false); var loginsDict = syncResponse.Result.Ciphers.Where(c => c.Type == Enums.CipherType.Login)
var folders = await _folderApiRepository.GetAsync().ConfigureAwait(false); .ToDictionary(s => s.Id);
var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false); var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
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 loginTask = SyncLoginsAsync(loginsDict); var loginTask = SyncLoginsAsync(loginsDict);
var folderTask = SyncFoldersAsync(foldersDict); var folderTask = SyncFoldersAsync(foldersDict);
var domainsTask = SyncDomainsAsync(domains.Result); var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
var profileTask = SyncProfileKeysAsync(profile.Result); var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile);
await Task.WhenAll(loginTask, folderTask, domainsTask, profileTask).ConfigureAwait(false); await Task.WhenAll(loginTask, folderTask, domainsTask, profileTask).ConfigureAwait(false);
if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null || if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null ||
@ -436,6 +430,11 @@ namespace Bit.App.Services
private async Task SyncDomainsAsync(DomainsResponse serverDomains) private async Task SyncDomainsAsync(DomainsResponse serverDomains)
{ {
if(serverDomains == null)
{
return;
}
var eqDomains = new List<IEnumerable<string>>(); var eqDomains = new List<IEnumerable<string>>();
if(serverDomains.EquivalentDomains != null) if(serverDomains.EquivalentDomains != null)
{ {
@ -460,6 +459,11 @@ namespace Bit.App.Services
private Task SyncProfileKeysAsync(ProfileResponse profile) private Task SyncProfileKeysAsync(ProfileResponse profile)
{ {
if(profile == null)
{
return Task.FromResult(0);
}
if(!string.IsNullOrWhiteSpace(profile.Key)) if(!string.IsNullOrWhiteSpace(profile.Key))
{ {
_cryptoService.SetEncKey(new CipherString(profile.Key)); _cryptoService.SetEncKey(new CipherString(profile.Key));

View file

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

View file

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