mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-27 12:26:31 +01:00
change syncing to use new sync api
This commit is contained in:
parent
45d171e0e3
commit
a426d98e92
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
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>
|
||||
<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" />
|
||||
|
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 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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user