mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 23:31:52 +03:00
Init HttpClient with each Api Request. Guarg agsint connectivity issues when making API calls.
This commit is contained in:
parent
a4e6f49959
commit
7d62a89a51
15 changed files with 402 additions and 172 deletions
|
@ -10,6 +10,8 @@ using Bit.App.Abstractions;
|
|||
using XLabs.Ioc;
|
||||
using Plugin.Fingerprint.Abstractions;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
using Acr.UserDialogs;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
|
@ -25,6 +27,8 @@ namespace Bit.Android
|
|||
|
||||
LoadApplication(new App.App(
|
||||
Resolver.Resolve<IAuthService>(),
|
||||
Resolver.Resolve<IConnectivity>(),
|
||||
Resolver.Resolve<IUserDialogs>(),
|
||||
Resolver.Resolve<IDatabaseService>(),
|
||||
Resolver.Resolve<ISyncService>(),
|
||||
Resolver.Resolve<IFingerprint>(),
|
||||
|
|
|
@ -14,6 +14,6 @@ namespace Bit.App.Abstractions
|
|||
Task<ApiResult<ListResponse<TResponse>>> GetAsync();
|
||||
Task<ApiResult<TResponse>> PostAsync(TRequest requestObj);
|
||||
Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj);
|
||||
Task<ApiResult<object>> DeleteAsync(TId id);
|
||||
Task<ApiResult> DeleteAsync(TId id);
|
||||
}
|
||||
}
|
|
@ -10,12 +10,17 @@ using Plugin.Fingerprint.Abstractions;
|
|||
using System.Threading.Tasks;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
using System.Net;
|
||||
using Acr.UserDialogs;
|
||||
|
||||
namespace Bit.App
|
||||
{
|
||||
public class App : Application
|
||||
{
|
||||
private readonly IDatabaseService _databaseService;
|
||||
private readonly IConnectivity _connectivity;
|
||||
private readonly IUserDialogs _userDialogs;
|
||||
private readonly ISyncService _syncService;
|
||||
private readonly IAuthService _authService;
|
||||
private readonly IFingerprint _fingerprint;
|
||||
|
@ -23,12 +28,16 @@ namespace Bit.App
|
|||
|
||||
public App(
|
||||
IAuthService authService,
|
||||
IConnectivity connectivity,
|
||||
IUserDialogs userDialogs,
|
||||
IDatabaseService databaseService,
|
||||
ISyncService syncService,
|
||||
IFingerprint fingerprint,
|
||||
ISettings settings)
|
||||
{
|
||||
_databaseService = databaseService;
|
||||
_connectivity = connectivity;
|
||||
_userDialogs = userDialogs;
|
||||
_syncService = syncService;
|
||||
_authService = authService;
|
||||
_fingerprint = fingerprint;
|
||||
|
@ -47,9 +56,36 @@ namespace Bit.App
|
|||
|
||||
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
|
||||
{
|
||||
var syncTask = _syncService.IncrementalSyncAsync();
|
||||
await CheckLockAsync(args);
|
||||
await syncTask;
|
||||
if(_connectivity.IsConnected)
|
||||
{
|
||||
var attempt = 0;
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
await _syncService.IncrementalSyncAsync();
|
||||
break;
|
||||
}
|
||||
catch(WebException)
|
||||
{
|
||||
Debug.WriteLine("Failed to sync.");
|
||||
if(attempt >= 1)
|
||||
{
|
||||
await _userDialogs.AlertAsync("Unable to automatically sync.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
attempt++;
|
||||
}
|
||||
} while(attempt <= 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("Not connected.");
|
||||
}
|
||||
});
|
||||
|
||||
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", async (sender, args) =>
|
||||
|
@ -58,12 +94,35 @@ namespace Bit.App
|
|||
});
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
protected async override void OnStart()
|
||||
{
|
||||
// Handle when your app starts
|
||||
var lockTask = CheckLockAsync(false);
|
||||
await CheckLockAsync(false);
|
||||
_databaseService.CreateTables();
|
||||
var syncTask = _syncService.FullSyncAsync();
|
||||
if(_connectivity.IsConnected)
|
||||
{
|
||||
var attempt = 0;
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
await _syncService.FullSyncAsync();
|
||||
break;
|
||||
}
|
||||
catch(WebException)
|
||||
{
|
||||
if(attempt >= 1)
|
||||
{
|
||||
await _userDialogs.AlertAsync("Unable to automatically sync. Manual sync required.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
attempt++;
|
||||
}
|
||||
} while(attempt <= 1);
|
||||
}
|
||||
|
||||
Debug.WriteLine("OnStart");
|
||||
}
|
||||
|
@ -79,14 +138,14 @@ namespace Bit.App
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
protected async override void OnResume()
|
||||
{
|
||||
// Handle when your app resumes
|
||||
Debug.WriteLine("OnResume");
|
||||
|
||||
if(Device.OS == TargetPlatform.Android)
|
||||
{
|
||||
var task = CheckLockAsync(false);
|
||||
await CheckLockAsync(false);
|
||||
}
|
||||
|
||||
var lockPinPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as LockPinPage;
|
||||
|
|
|
@ -157,6 +157,7 @@
|
|||
<Compile Include="Pages\VaultListSitesPage.cs" />
|
||||
<Compile Include="Utilities\Extentions.cs" />
|
||||
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
|
||||
<Compile Include="Utilities\ApiHttpClient.cs" />
|
||||
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -12,6 +12,7 @@ using XLabs.Ioc;
|
|||
using Bit.App.Utilities;
|
||||
using PushNotification.Plugin.Abstractions;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -20,6 +21,7 @@ namespace Bit.App.Pages
|
|||
private readonly IFolderService _folderService;
|
||||
private readonly ISiteService _siteService;
|
||||
private readonly IUserDialogs _userDialogs;
|
||||
private readonly IConnectivity _connectivity;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
private readonly IPushNotification _pushNotification;
|
||||
private readonly ISettings _settings;
|
||||
|
@ -30,6 +32,7 @@ namespace Bit.App.Pages
|
|||
_favorites = favorites;
|
||||
_folderService = Resolver.Resolve<IFolderService>();
|
||||
_siteService = Resolver.Resolve<ISiteService>();
|
||||
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||
_clipboardService = Resolver.Resolve<IClipboardService>();
|
||||
_pushNotification = Resolver.Resolve<IPushNotification>();
|
||||
|
@ -77,7 +80,7 @@ namespace Bit.App.Pages
|
|||
base.OnAppearing();
|
||||
LoadFoldersAsync().Wait();
|
||||
|
||||
if(Device.OS == TargetPlatform.iOS && !_favorites)
|
||||
if(_connectivity.IsConnected && Device.OS == TargetPlatform.iOS && !_favorites)
|
||||
{
|
||||
if(!_settings.GetValueOrDefault<bool>(Constants.PushPromptShown))
|
||||
{
|
||||
|
|
|
@ -3,28 +3,41 @@ using System.Net.Http;
|
|||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class AccountsApiRepository : BaseApiRepository, IAccountsApiRepository
|
||||
{
|
||||
public AccountsApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "accounts";
|
||||
|
||||
public virtual async Task<ApiResult> PostRegisterAsync(RegisterRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/register")),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync(response);
|
||||
return HandledNotConnected();
|
||||
}
|
||||
|
||||
return ApiResult.Success(response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/register")),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync(response);
|
||||
}
|
||||
|
||||
return ApiResult.Success(response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
|||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
|
@ -13,100 +14,141 @@ namespace Bit.App.Repositories
|
|||
where TRequest : class
|
||||
where TResponse : class
|
||||
{
|
||||
public ApiRepository()
|
||||
public ApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
public virtual async Task<ApiResult<TResponse>> GetByIdAsync(TId id)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
return HandledNotConnected<TResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<ListResponse<TResponse>>> GetAsync()
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<TResponse>>(response);
|
||||
return HandledNotConnected<ListResponse<TResponse>>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<TResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<TResponse>>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<TResponse>>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<TResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<TResponse>>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<TResponse>> PostAsync(TRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
return HandledNotConnected<TResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<TResponse>> PutAsync(TId id, TRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
return HandledNotConnected<TResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TResponse>(responseContent);
|
||||
return ApiResult<TResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<object>> DeleteAsync(TId id)
|
||||
public virtual async Task<ApiResult> DeleteAsync(TId id)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Delete,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<object>(response);
|
||||
return HandledNotConnected();
|
||||
}
|
||||
|
||||
return ApiResult<object>.Success(null, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Delete,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync(response);
|
||||
}
|
||||
|
||||
return ApiResult.Success(response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,49 +4,70 @@ using System.Threading.Tasks;
|
|||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class AuthApiRepository : BaseApiRepository, IAuthApiRepository
|
||||
{
|
||||
public AuthApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "auth";
|
||||
|
||||
public virtual async Task<ApiResult<TokenResponse>> PostTokenAsync(TokenRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TokenResponse>(response);
|
||||
return HandledNotConnected<TokenResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TokenResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<TokenResponse>> PostTokenTwoFactorAsync(TokenTwoFactorRequest requestObj)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/token/two-factor")),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TokenResponse>(response);
|
||||
return HandledNotConnected<TokenResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(requestObj)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token/two-factor")),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<TokenResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Models.Api;
|
||||
using ModernHttpClient;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public abstract class BaseApiRepository
|
||||
{
|
||||
public BaseApiRepository()
|
||||
public BaseApiRepository(IConnectivity connectivity)
|
||||
{
|
||||
Client = new HttpClient(new NativeMessageHandler());
|
||||
Client.BaseAddress = new Uri("https://api.bitwarden.com");
|
||||
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
Connectivity = connectivity;
|
||||
}
|
||||
|
||||
protected virtual HttpClient Client { get; private set; }
|
||||
protected IConnectivity Connectivity { get; private set; }
|
||||
protected abstract string ApiRoute { get; }
|
||||
|
||||
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
||||
protected ApiResult HandledNotConnected()
|
||||
{
|
||||
return ApiResult.Failed(System.Net.HttpStatusCode.RequestTimeout, new ApiError { Message = "Not connected to the internet." });
|
||||
}
|
||||
|
||||
protected ApiResult<T> HandledNotConnected<T>()
|
||||
{
|
||||
return ApiResult<T>.Failed(System.Net.HttpStatusCode.RequestTimeout, new ApiError { Message = "Not connected to the internet." });
|
||||
}
|
||||
|
||||
protected async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -34,7 +41,7 @@ namespace Bit.App.Repositories
|
|||
return ApiResult<T>.Failed(response.StatusCode, new ApiError { Message = "An unknown error has occured." });
|
||||
}
|
||||
|
||||
public async Task<ApiResult> HandleErrorAsync(HttpResponseMessage response)
|
||||
protected async Task<ApiResult> HandleErrorAsync(HttpResponseMessage response)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -5,68 +5,97 @@ using System.Threading.Tasks;
|
|||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class CipherApiRepository : BaseApiRepository, ICipherApiRepository
|
||||
{
|
||||
public CipherApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "ciphers";
|
||||
|
||||
public virtual async Task<ApiResult<CipherResponse>> GetByIdAsync(string id)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<CipherResponse>(response);
|
||||
return HandledNotConnected<CipherResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<CipherResponse>(responseContent);
|
||||
return ApiResult<CipherResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<CipherResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<CipherResponse>(responseContent);
|
||||
return ApiResult<CipherResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<ListResponse<CipherResponse>>> GetAsync()
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<CipherResponse>>(response);
|
||||
return HandledNotConnected<ListResponse<CipherResponse>>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<CipherResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<CipherResponse>>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<CipherResponse>>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<CipherResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<CipherResponse>>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<ApiResult<CipherHistoryResponse>> GetByRevisionDateWithHistoryAsync(DateTime since)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/history", "?since=", since)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<CipherHistoryResponse>(response);
|
||||
return HandledNotConnected<CipherHistoryResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<CipherHistoryResponse>(responseContent);
|
||||
return ApiResult<CipherHistoryResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/history", "?since=", since)),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<CipherHistoryResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<CipherHistoryResponse>(responseContent);
|
||||
return ApiResult<CipherHistoryResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,30 +4,43 @@ using System.Threading.Tasks;
|
|||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class DeviceApiRepository : ApiRepository<DeviceRequest, DeviceResponse, string>, IDeviceApiRepository
|
||||
{
|
||||
public DeviceApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "devices";
|
||||
|
||||
public virtual async Task<ApiResult<DeviceResponse>> PutTokenAsync(string identifier, DeviceTokenRequest request)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(request)
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/identifier/", identifier, "/token")),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<DeviceResponse>(response);
|
||||
return HandledNotConnected<DeviceResponse>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<DeviceResponse>(responseContent);
|
||||
return ApiResult<DeviceResponse>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage(request)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/identifier/", identifier, "/token")),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<DeviceResponse>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<DeviceResponse>(responseContent);
|
||||
return ApiResult<DeviceResponse>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,30 +5,43 @@ using System.Threading.Tasks;
|
|||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class FolderApiRepository : ApiRepository<FolderRequest, FolderResponse, string>, IFolderApiRepository
|
||||
{
|
||||
public FolderApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "folders";
|
||||
|
||||
public virtual async Task<ApiResult<ListResponse<FolderResponse>>> GetByRevisionDateAsync(DateTime since)
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
if(!Connectivity.IsConnected)
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
||||
};
|
||||
|
||||
var response = await Client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<FolderResponse>>(response);
|
||||
return HandledNotConnected<ListResponse<FolderResponse>>();
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<FolderResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<FolderResponse>>.Success(responseObj, response.StatusCode);
|
||||
using(var client = new ApiHttpClient())
|
||||
{
|
||||
var requestMessage = new TokenHttpRequestMessage()
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(requestMessage);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await HandleErrorAsync<ListResponse<FolderResponse>>(response);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<FolderResponse>>(responseContent);
|
||||
return ApiResult<ListResponse<FolderResponse>>.Success(responseObj, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,16 @@ using System.Threading.Tasks;
|
|||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public class SiteApiRepository : ApiRepository<SiteRequest, SiteResponse, string>, ISiteApiRepository
|
||||
{
|
||||
public SiteApiRepository(IConnectivity connectivity)
|
||||
: base(connectivity)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "sites";
|
||||
}
|
||||
}
|
||||
|
|
17
src/App/Utilities/ApiHttpClient.cs
Normal file
17
src/App/Utilities/ApiHttpClient.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System.Net.Http;
|
||||
using ModernHttpClient;
|
||||
using System;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Bit.App
|
||||
{
|
||||
public class ApiHttpClient : HttpClient
|
||||
{
|
||||
public ApiHttpClient()
|
||||
: base(new NativeMessageHandler())
|
||||
{
|
||||
BaseAddress = new Uri("https://api.bitwarden.com");
|
||||
DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ using Bit.App;
|
|||
using Bit.iOS.Core.Services;
|
||||
using PushNotification.Plugin;
|
||||
using Plugin.DeviceInfo;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
|
||||
namespace Bit.iOS
|
||||
{
|
||||
|
@ -43,6 +44,8 @@ namespace Bit.iOS
|
|||
|
||||
LoadApplication(new App.App(
|
||||
Resolver.Resolve<IAuthService>(),
|
||||
Resolver.Resolve<IConnectivity>(),
|
||||
Resolver.Resolve<IUserDialogs>(),
|
||||
Resolver.Resolve<IDatabaseService>(),
|
||||
Resolver.Resolve<ISyncService>(),
|
||||
Resolver.Resolve<IFingerprint>(),
|
||||
|
|
Loading…
Reference in a new issue