mirror of
https://github.com/bitwarden/android.git
synced 2024-12-19 07:41:52 +03:00
centralize login code into auth service
This commit is contained in:
parent
8e29a990cb
commit
0ebfe85d8e
10 changed files with 114 additions and 161 deletions
|
@ -8,6 +8,5 @@ namespace Bit.App.Abstractions
|
||||||
{
|
{
|
||||||
Task<ApiResult<CipherResponse>> GetByIdAsync(string id);
|
Task<ApiResult<CipherResponse>> GetByIdAsync(string id);
|
||||||
Task<ApiResult<ListResponse<CipherResponse>>> GetAsync();
|
Task<ApiResult<ListResponse<CipherResponse>>> GetAsync();
|
||||||
Task<ApiResult<CipherHistoryResponse>> GetByRevisionDateWithHistoryAsync(DateTime since);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Threading.Tasks;
|
using Bit.App.Models;
|
||||||
using Bit.App.Models.Api;
|
using System.Threading.Tasks;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Bit.App.Abstractions
|
namespace Bit.App.Abstractions
|
||||||
{
|
{
|
||||||
|
@ -14,6 +13,7 @@ namespace Bit.App.Abstractions
|
||||||
string PIN { get; set; }
|
string PIN { get; set; }
|
||||||
|
|
||||||
void LogOut();
|
void LogOut();
|
||||||
Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request);
|
Task<FullLoginResult> TokenPostAsync(string email, string masterPassword);
|
||||||
|
Task<LoginResult> TokenPostTwoFactorAsync(string token, string email, string masterPasswordHash, byte[] key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@
|
||||||
<Compile Include="Models\Data\LoginData.cs" />
|
<Compile Include="Models\Data\LoginData.cs" />
|
||||||
<Compile Include="Models\DomainName.cs" />
|
<Compile Include="Models\DomainName.cs" />
|
||||||
<Compile Include="Models\Folder.cs" />
|
<Compile Include="Models\Folder.cs" />
|
||||||
|
<Compile Include="Models\LoginResult.cs" />
|
||||||
<Compile Include="Models\Page\AppExtensionPageModel.cs" />
|
<Compile Include="Models\Page\AppExtensionPageModel.cs" />
|
||||||
<Compile Include="Models\Page\SettingsFolderPageModel.cs" />
|
<Compile Include="Models\Page\SettingsFolderPageModel.cs" />
|
||||||
<Compile Include="Models\Page\PinPageModel.cs" />
|
<Compile Include="Models\Page\PinPageModel.cs" />
|
||||||
|
|
|
@ -14,5 +14,6 @@ namespace Bit.App.Models.Api
|
||||||
[JsonProperty("token_type")]
|
[JsonProperty("token_type")]
|
||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
public List<int> TwoFactorProviders { get; set; }
|
public List<int> TwoFactorProviders { get; set; }
|
||||||
|
public string PrivateKey { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/App/Models/LoginResult.cs
Normal file
15
src/App/Models/LoginResult.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class LoginResult
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FullLoginResult : LoginResult
|
||||||
|
{
|
||||||
|
public bool TwoFactorRequired { get; set; }
|
||||||
|
public byte[] Key { get; set; }
|
||||||
|
public string MasterPasswordHash { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Bit.App.Models.Api;
|
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
@ -15,11 +13,7 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class LoginPage : ExtendedContentPage
|
public class LoginPage : ExtendedContentPage
|
||||||
{
|
{
|
||||||
private ICryptoService _cryptoService;
|
|
||||||
private IAuthService _authService;
|
private IAuthService _authService;
|
||||||
private ITokenService _tokenService;
|
|
||||||
private IDeviceInfoService _deviceInfoService;
|
|
||||||
private IAppIdService _appIdService;
|
|
||||||
private IUserDialogs _userDialogs;
|
private IUserDialogs _userDialogs;
|
||||||
private ISyncService _syncService;
|
private ISyncService _syncService;
|
||||||
private ISettings _settings;
|
private ISettings _settings;
|
||||||
|
@ -31,11 +25,7 @@ namespace Bit.App.Pages
|
||||||
: base(updateActivity: false)
|
: base(updateActivity: false)
|
||||||
{
|
{
|
||||||
_email = email;
|
_email = email;
|
||||||
_cryptoService = Resolver.Resolve<ICryptoService>();
|
|
||||||
_authService = Resolver.Resolve<IAuthService>();
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
_tokenService = Resolver.Resolve<ITokenService>();
|
|
||||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
|
||||||
_appIdService = Resolver.Resolve<IAppIdService>();
|
|
||||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
_syncService = Resolver.Resolve<ISyncService>();
|
_syncService = Resolver.Resolve<ISyncService>();
|
||||||
_settings = Resolver.Resolve<ISettings>();
|
_settings = Resolver.Resolve<ISettings>();
|
||||||
|
@ -188,39 +178,22 @@ namespace Bit.App.Pages
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var normalizedEmail = EmailCell.Entry.Text.ToLower();
|
|
||||||
|
|
||||||
var key = _cryptoService.MakeKeyFromPassword(PasswordCell.Entry.Text, normalizedEmail);
|
|
||||||
|
|
||||||
var request = new TokenRequest
|
|
||||||
{
|
|
||||||
Email = normalizedEmail,
|
|
||||||
MasterPasswordHash = _cryptoService.HashPasswordBase64(key, PasswordCell.Entry.Text),
|
|
||||||
Device = new DeviceRequest(_appIdService, _deviceInfoService)
|
|
||||||
};
|
|
||||||
|
|
||||||
_userDialogs.ShowLoading(AppResources.LoggingIn, MaskType.Black);
|
_userDialogs.ShowLoading(AppResources.LoggingIn, MaskType.Black);
|
||||||
var response = await _authService.TokenPostAsync(request);
|
var result = await _authService.TokenPostAsync(EmailCell.Entry.Text, PasswordCell.Entry.Text);
|
||||||
_userDialogs.HideLoading();
|
_userDialogs.HideLoading();
|
||||||
if(!response.Succeeded)
|
if(!result.Success)
|
||||||
{
|
{
|
||||||
await DisplayAlert(AppResources.AnErrorHasOccurred, response.Errors.FirstOrDefault()?.Message, AppResources.Ok);
|
await DisplayAlert(AppResources.AnErrorHasOccurred, result.ErrorMessage, AppResources.Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(response.Result.TwoFactorProviders != null && response.Result.TwoFactorProviders.Count > 0)
|
if(result.TwoFactorRequired)
|
||||||
{
|
{
|
||||||
_googleAnalyticsService.TrackAppEvent("LoggedIn To Two-step");
|
_googleAnalyticsService.TrackAppEvent("LoggedIn To Two-step");
|
||||||
await Navigation.PushAsync(new LoginTwoFactorPage(request.Email, request.MasterPasswordHash, key));
|
await Navigation.PushAsync(new LoginTwoFactorPage(EmailCell.Entry.Text, result.MasterPasswordHash, result.Key));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cryptoService.Key = key;
|
|
||||||
_tokenService.Token = response.Result.AccessToken;
|
|
||||||
_tokenService.RefreshToken = response.Result.RefreshToken;
|
|
||||||
_authService.UserId = _tokenService.TokenUserId;
|
|
||||||
_authService.Email = _tokenService.TokenEmail;
|
|
||||||
_settings.AddOrUpdateValue(Constants.LastLoginEmail, _authService.Email);
|
|
||||||
_googleAnalyticsService.TrackAppEvent("LoggedIn");
|
_googleAnalyticsService.TrackAppEvent("LoggedIn");
|
||||||
|
|
||||||
if(Device.OS == TargetPlatform.Android)
|
if(Device.OS == TargetPlatform.Android)
|
||||||
|
|
|
@ -1,28 +1,20 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Bit.App.Models.Api;
|
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Plugin.Settings.Abstractions;
|
|
||||||
using PushNotification.Plugin.Abstractions;
|
using PushNotification.Plugin.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class LoginTwoFactorPage : ExtendedContentPage
|
public class LoginTwoFactorPage : ExtendedContentPage
|
||||||
{
|
{
|
||||||
private ICryptoService _cryptoService;
|
|
||||||
private IAuthService _authService;
|
private IAuthService _authService;
|
||||||
private ITokenService _tokenService;
|
|
||||||
private IDeviceInfoService _deviceInfoService;
|
|
||||||
private IAppIdService _appIdService;
|
|
||||||
private IUserDialogs _userDialogs;
|
private IUserDialogs _userDialogs;
|
||||||
private ISyncService _syncService;
|
private ISyncService _syncService;
|
||||||
private ISettings _settings;
|
|
||||||
private IGoogleAnalyticsService _googleAnalyticsService;
|
private IGoogleAnalyticsService _googleAnalyticsService;
|
||||||
private IPushNotification _pushNotification;
|
private IPushNotification _pushNotification;
|
||||||
private readonly string _email;
|
private readonly string _email;
|
||||||
|
@ -36,14 +28,9 @@ namespace Bit.App.Pages
|
||||||
_masterPasswordHash = masterPasswordHash;
|
_masterPasswordHash = masterPasswordHash;
|
||||||
_key = key;
|
_key = key;
|
||||||
|
|
||||||
_cryptoService = Resolver.Resolve<ICryptoService>();
|
|
||||||
_authService = Resolver.Resolve<IAuthService>();
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
_tokenService = Resolver.Resolve<ITokenService>();
|
|
||||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
|
||||||
_appIdService = Resolver.Resolve<IAppIdService>();
|
|
||||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
_syncService = Resolver.Resolve<ISyncService>();
|
_syncService = Resolver.Resolve<ISyncService>();
|
||||||
_settings = Resolver.Resolve<ISettings>();
|
|
||||||
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
|
||||||
_pushNotification = Resolver.Resolve<IPushNotification>();
|
_pushNotification = Resolver.Resolve<IPushNotification>();
|
||||||
|
|
||||||
|
@ -117,7 +104,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
var continueToolbarItem = new ToolbarItem(AppResources.Continue, null, async () =>
|
var continueToolbarItem = new ToolbarItem(AppResources.Continue, null, async () =>
|
||||||
{
|
{
|
||||||
await LogIn();
|
await LogInAsync();
|
||||||
}, ToolbarItemOrder.Default, 0);
|
}, ToolbarItemOrder.Default, 0);
|
||||||
|
|
||||||
ToolbarItems.Add(continueToolbarItem);
|
ToolbarItems.Add(continueToolbarItem);
|
||||||
|
@ -147,10 +134,10 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
private async void Entry_Completed(object sender, EventArgs e)
|
private async void Entry_Completed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
await LogIn();
|
await LogInAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LogIn()
|
private async Task LogInAsync()
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(CodeCell.Entry.Text))
|
if(string.IsNullOrWhiteSpace(CodeCell.Entry.Text))
|
||||||
{
|
{
|
||||||
|
@ -159,30 +146,15 @@ namespace Bit.App.Pages
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = new TokenRequest
|
|
||||||
{
|
|
||||||
Email = _email,
|
|
||||||
MasterPasswordHash = _masterPasswordHash,
|
|
||||||
Token = CodeCell.Entry.Text.Replace(" ", ""),
|
|
||||||
Provider = 0, // Authenticator app (only 1 provider for now, so hard coded)
|
|
||||||
Device = new DeviceRequest(_appIdService, _deviceInfoService)
|
|
||||||
};
|
|
||||||
|
|
||||||
_userDialogs.ShowLoading(AppResources.ValidatingCode, MaskType.Black);
|
_userDialogs.ShowLoading(AppResources.ValidatingCode, MaskType.Black);
|
||||||
var response = await _authService.TokenPostAsync(request);
|
var response = await _authService.TokenPostTwoFactorAsync(CodeCell.Entry.Text, _email, _masterPasswordHash, _key);
|
||||||
_userDialogs.HideLoading();
|
_userDialogs.HideLoading();
|
||||||
if(!response.Succeeded)
|
if(!response.Success)
|
||||||
{
|
{
|
||||||
await DisplayAlert(AppResources.AnErrorHasOccurred, response.Errors.FirstOrDefault()?.Message, AppResources.Ok);
|
await DisplayAlert(AppResources.AnErrorHasOccurred, response.ErrorMessage, AppResources.Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cryptoService.Key = _key;
|
|
||||||
_tokenService.Token = response.Result.AccessToken;
|
|
||||||
_tokenService.RefreshToken = response.Result.RefreshToken;
|
|
||||||
_authService.UserId = _tokenService.TokenUserId;
|
|
||||||
_authService.Email = _tokenService.TokenEmail;
|
|
||||||
_settings.AddOrUpdateValue(Constants.LastLoginEmail, _authService.Email);
|
|
||||||
_googleAnalyticsService.TrackAppEvent("LoggedIn From Two-step");
|
_googleAnalyticsService.TrackAppEvent("LoggedIn From Two-step");
|
||||||
|
|
||||||
if(Device.OS == TargetPlatform.Android)
|
if(Device.OS == TargetPlatform.Android)
|
||||||
|
|
|
@ -77,7 +77,8 @@ namespace Bit.App.Repositories
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
var requestMessage = new TokenHttpRequestMessage()
|
||||||
{
|
{
|
||||||
Method = HttpMethod.Get,
|
Method = HttpMethod.Get,
|
||||||
RequestUri = new Uri(client.BaseAddress, ApiRoute),
|
RequestUri = new Uri(client.BaseAddress,
|
||||||
|
string.Format("{0}?includeFolders=false&includeShared=true", ApiRoute)),
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -98,45 +99,5 @@ namespace Bit.App.Repositories
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<ApiResult<CipherHistoryResponse>> GetByRevisionDateWithHistoryAsync(DateTime since)
|
|
||||||
{
|
|
||||||
if(!Connectivity.IsConnected)
|
|
||||||
{
|
|
||||||
return HandledNotConnected<CipherHistoryResponse>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenStateResponse = await HandleTokenStateAsync<CipherHistoryResponse>();
|
|
||||||
if(!tokenStateResponse.Succeeded)
|
|
||||||
{
|
|
||||||
return tokenStateResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
using(var client = HttpService.Client)
|
|
||||||
{
|
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
|
||||||
{
|
|
||||||
Method = HttpMethod.Get,
|
|
||||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/history", "?since=", since)),
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
|
||||||
if(!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return await HandleErrorAsync<CipherHistoryResponse>(response).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
||||||
var responseObj = JsonConvert.DeserializeObject<CipherHistoryResponse>(responseContent);
|
|
||||||
return ApiResult<CipherHistoryResponse>.Success(responseObj, response.StatusCode);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return HandledWebException<CipherHistoryResponse>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Plugin.Connectivity.Abstractions;
|
using Plugin.Connectivity.Abstractions;
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace Bit.App.Repositories
|
namespace Bit.App.Repositories
|
||||||
{
|
{
|
||||||
|
@ -20,45 +15,5 @@ namespace Bit.App.Repositories
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
protected override string ApiRoute => "folders";
|
protected override string ApiRoute => "folders";
|
||||||
|
|
||||||
public virtual async Task<ApiResult<ListResponse<FolderResponse>>> GetByRevisionDateAsync(DateTime since)
|
|
||||||
{
|
|
||||||
if(!Connectivity.IsConnected)
|
|
||||||
{
|
|
||||||
return HandledNotConnected<ListResponse<FolderResponse>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenStateResponse = await HandleTokenStateAsync<ListResponse<FolderResponse>>();
|
|
||||||
if(!tokenStateResponse.Succeeded)
|
|
||||||
{
|
|
||||||
return tokenStateResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
using(var client = HttpService.Client)
|
|
||||||
{
|
|
||||||
var requestMessage = new TokenHttpRequestMessage()
|
|
||||||
{
|
|
||||||
Method = HttpMethod.Get,
|
|
||||||
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "?since=", since)),
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
|
|
||||||
if(!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return await HandleErrorAsync<ListResponse<FolderResponse>>(response).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
||||||
var responseObj = JsonConvert.DeserializeObject<ListResponse<FolderResponse>>(responseContent);
|
|
||||||
return ApiResult<ListResponse<FolderResponse>>.Success(responseObj, response.StatusCode);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return HandledWebException<ListResponse<FolderResponse>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,10 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using System.Linq;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using PushNotification.Plugin.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
|
@ -19,6 +23,8 @@ namespace Bit.App.Services
|
||||||
private readonly ISettings _settings;
|
private readonly ISettings _settings;
|
||||||
private readonly ICryptoService _cryptoService;
|
private readonly ICryptoService _cryptoService;
|
||||||
private readonly IConnectApiRepository _connectApiRepository;
|
private readonly IConnectApiRepository _connectApiRepository;
|
||||||
|
private readonly IAppIdService _appIdService;
|
||||||
|
private readonly IDeviceInfoService _deviceInfoService;
|
||||||
|
|
||||||
private string _email;
|
private string _email;
|
||||||
private string _userId;
|
private string _userId;
|
||||||
|
@ -30,13 +36,17 @@ namespace Bit.App.Services
|
||||||
ITokenService tokenService,
|
ITokenService tokenService,
|
||||||
ISettings settings,
|
ISettings settings,
|
||||||
ICryptoService cryptoService,
|
ICryptoService cryptoService,
|
||||||
IConnectApiRepository connectApiRepository)
|
IConnectApiRepository connectApiRepository,
|
||||||
|
IAppIdService appIdService,
|
||||||
|
IDeviceInfoService deviceInfoService)
|
||||||
{
|
{
|
||||||
_secureStorage = secureStorage;
|
_secureStorage = secureStorage;
|
||||||
_tokenService = tokenService;
|
_tokenService = tokenService;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_cryptoService = cryptoService;
|
_cryptoService = cryptoService;
|
||||||
_connectApiRepository = connectApiRepository;
|
_connectApiRepository = connectApiRepository;
|
||||||
|
_appIdService = appIdService;
|
||||||
|
_deviceInfoService = deviceInfoService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UserId
|
public string UserId
|
||||||
|
@ -191,10 +201,76 @@ namespace Bit.App.Services
|
||||||
_settings.Remove(Constants.Locked);
|
_settings.Remove(Constants.Locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request)
|
public async Task<FullLoginResult> TokenPostAsync(string email, string masterPassword)
|
||||||
{
|
{
|
||||||
// TODO: move more logic in here
|
var result = new FullLoginResult();
|
||||||
return await _connectApiRepository.PostTokenAsync(request);
|
|
||||||
|
var normalizedEmail = email.Trim().ToLower();
|
||||||
|
var key = _cryptoService.MakeKeyFromPassword(masterPassword, normalizedEmail);
|
||||||
|
|
||||||
|
var request = new TokenRequest
|
||||||
|
{
|
||||||
|
Email = normalizedEmail,
|
||||||
|
MasterPasswordHash = _cryptoService.HashPasswordBase64(key, masterPassword),
|
||||||
|
Device = new DeviceRequest(_appIdService, _deviceInfoService)
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _connectApiRepository.PostTokenAsync(request);
|
||||||
|
if(!response.Succeeded)
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
result.ErrorMessage = response.Errors.FirstOrDefault()?.Message;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Success = true;
|
||||||
|
if(response.Result.TwoFactorProviders != null && response.Result.TwoFactorProviders.Count > 0)
|
||||||
|
{
|
||||||
|
result.Key = key;
|
||||||
|
result.MasterPasswordHash = request.MasterPasswordHash;
|
||||||
|
result.TwoFactorRequired = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessLoginSuccess(key, response.Result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<LoginResult> TokenPostTwoFactorAsync(string token, string email, string masterPasswordHash,
|
||||||
|
byte[] key)
|
||||||
|
{
|
||||||
|
var result = new LoginResult();
|
||||||
|
|
||||||
|
var request = new TokenRequest
|
||||||
|
{
|
||||||
|
Email = email.Trim().ToLower(),
|
||||||
|
MasterPasswordHash = masterPasswordHash,
|
||||||
|
Token = token.Trim().Replace(" ", ""),
|
||||||
|
Provider = 0, // Authenticator app (only 1 provider for now, so hard coded)
|
||||||
|
Device = new DeviceRequest(_appIdService, _deviceInfoService)
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _connectApiRepository.PostTokenAsync(request);
|
||||||
|
if(!response.Succeeded)
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
result.ErrorMessage = response.Errors.FirstOrDefault()?.Message;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Success = true;
|
||||||
|
ProcessLoginSuccess(key, response.Result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessLoginSuccess(byte[] key, TokenResponse response)
|
||||||
|
{
|
||||||
|
_cryptoService.Key = key;
|
||||||
|
_tokenService.Token = response.AccessToken;
|
||||||
|
_tokenService.RefreshToken = response.RefreshToken;
|
||||||
|
UserId = _tokenService.TokenUserId;
|
||||||
|
Email = _tokenService.TokenEmail;
|
||||||
|
_settings.AddOrUpdateValue(Constants.LastLoginEmail, Email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue