mirror of
https://github.com/bitwarden/mobile
synced 2026-01-05 18:13:36 +00:00
HandleTokenStateAsync before each API call for refresh and auth bearer migration
This commit is contained in:
@@ -6,42 +6,153 @@ using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
using Bit.App.Abstractions;
|
||||
using System.Net;
|
||||
using XLabs.Ioc;
|
||||
|
||||
namespace Bit.App.Repositories
|
||||
{
|
||||
public abstract class BaseApiRepository
|
||||
{
|
||||
public BaseApiRepository(IConnectivity connectivity, IHttpService httpService)
|
||||
public BaseApiRepository(
|
||||
IConnectivity connectivity,
|
||||
IHttpService httpService,
|
||||
ITokenService tokenService)
|
||||
{
|
||||
Connectivity = connectivity;
|
||||
HttpService = httpService;
|
||||
TokenService = tokenService;
|
||||
}
|
||||
|
||||
protected IConnectivity Connectivity { get; private set; }
|
||||
protected IHttpService HttpService { get; private set; }
|
||||
protected ITokenService TokenService { get; private set; }
|
||||
protected abstract string ApiRoute { get; }
|
||||
|
||||
protected async Task<ApiResult> HandleTokenStateAsync()
|
||||
{
|
||||
return await HandleTokenStateAsync(
|
||||
() => ApiResult.Success(HttpStatusCode.OK),
|
||||
() => HandledWebException(),
|
||||
(r) => HandleErrorAsync(r));
|
||||
}
|
||||
|
||||
protected async Task<ApiResult<T>> HandleTokenStateAsync<T>()
|
||||
{
|
||||
return await HandleTokenStateAsync(
|
||||
() => ApiResult<T>.Success(default(T), HttpStatusCode.OK),
|
||||
() => HandledWebException<T>(),
|
||||
(r) => HandleErrorAsync<T>(r));
|
||||
}
|
||||
|
||||
private async Task<T> HandleTokenStateAsync<T>(Func<T> success, Func<T> webException,
|
||||
Func<HttpResponseMessage, Task<T>> error)
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(TokenService.AuthBearer) && string.IsNullOrWhiteSpace(TokenService.Token))
|
||||
{
|
||||
// Migrate from old auth bearer to new access token
|
||||
|
||||
var deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||
var appIdService = Resolver.Resolve<IAppIdService>();
|
||||
|
||||
using(var client = HttpService.Client)
|
||||
{
|
||||
var requestMessage = new HttpRequestMessage
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
||||
Content = new FormUrlEncodedContent(new TokenRequest
|
||||
{
|
||||
Email = "abcdefgh",
|
||||
MasterPasswordHash = "abcdefgh",
|
||||
OldAuthBearer = TokenService.AuthBearer,
|
||||
Device = new DeviceRequest(appIdService, deviceInfoService)
|
||||
}.ToIdentityTokenRequest())
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await error.Invoke(response).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
TokenService.Token = tokenResponse.AccessToken;
|
||||
TokenService.RefreshToken = tokenResponse.RefreshToken;
|
||||
TokenService.AuthBearer = null;
|
||||
}
|
||||
catch(WebException)
|
||||
{
|
||||
return webException.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(TokenService.TokenNeedsRefresh && !string.IsNullOrWhiteSpace(TokenService.RefreshToken))
|
||||
{
|
||||
using(var client = HttpService.Client)
|
||||
{
|
||||
var requestMessage = new HttpRequestMessage
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token")),
|
||||
Content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "grant_type", "refresh_token" },
|
||||
{ "client_id", "mobile" },
|
||||
{ "refresh_token", TokenService.RefreshToken }
|
||||
})
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
if(!response.IsSuccessStatusCode)
|
||||
{
|
||||
return await error.Invoke(response).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||
TokenService.Token = tokenResponse.AccessToken;
|
||||
TokenService.RefreshToken = tokenResponse.RefreshToken;
|
||||
}
|
||||
catch(WebException)
|
||||
{
|
||||
return webException.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!string.IsNullOrWhiteSpace(TokenService.AuthBearer))
|
||||
{
|
||||
TokenService.AuthBearer = null;
|
||||
}
|
||||
|
||||
return success.Invoke();
|
||||
}
|
||||
|
||||
protected ApiResult HandledNotConnected()
|
||||
{
|
||||
return ApiResult.Failed(System.Net.HttpStatusCode.RequestTimeout,
|
||||
return ApiResult.Failed(HttpStatusCode.RequestTimeout,
|
||||
new ApiError { Message = "Not connected to the internet." });
|
||||
}
|
||||
|
||||
protected ApiResult<T> HandledNotConnected<T>()
|
||||
{
|
||||
return ApiResult<T>.Failed(System.Net.HttpStatusCode.RequestTimeout,
|
||||
return ApiResult<T>.Failed(HttpStatusCode.RequestTimeout,
|
||||
new ApiError { Message = "Not connected to the internet." });
|
||||
}
|
||||
|
||||
protected ApiResult HandledWebException()
|
||||
{
|
||||
return ApiResult.Failed(System.Net.HttpStatusCode.BadGateway,
|
||||
return ApiResult.Failed(HttpStatusCode.BadGateway,
|
||||
new ApiError { Message = "There is a problem connecting to the server." });
|
||||
}
|
||||
|
||||
protected ApiResult<T> HandledWebException<T>()
|
||||
{
|
||||
return ApiResult<T>.Failed(System.Net.HttpStatusCode.BadGateway,
|
||||
return ApiResult<T>.Failed(HttpStatusCode.BadGateway,
|
||||
new ApiError { Message = "There is a problem connecting to the server." });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user