mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 23:25:45 +03:00
change syncing to use new sync api
This commit is contained in:
parent
45d171e0e3
commit
a426d98e92
10 changed files with 114 additions and 60 deletions
|
@ -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);
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
10
src/App/Abstractions/Repositories/ISyncApiRepository.cs
Normal file
10
src/App/Abstractions/Repositories/ISyncApiRepository.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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" />
|
||||||
|
|
12
src/App/Models/Api/Response/SyncResponse.cs
Normal file
12
src/App/Models/Api/Response/SyncResponse.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
63
src/App/Repositories/SyncApiRepository.cs
Normal file
63
src/App/Repositories/SyncApiRepository.cs
Normal 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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue