From d112e0ea42181795929c1c3eb2a6f74a0c618127 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 6 Feb 2017 09:39:07 -0500 Subject: [PATCH] two-factor login re-worked with new auth flow --- src/App/Models/Api/Response/TokenResponse.cs | 2 ++ src/App/Pages/LoginPage.cs | 18 ++++++------ src/App/Pages/LoginTwoFactorPage.cs | 31 ++++++++++++++++++-- src/App/Repositories/ConnectApiRepository.cs | 14 ++++++++- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/App/Models/Api/Response/TokenResponse.cs b/src/App/Models/Api/Response/TokenResponse.cs index 92a05c2e8..92bc1cf6a 100644 --- a/src/App/Models/Api/Response/TokenResponse.cs +++ b/src/App/Models/Api/Response/TokenResponse.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.Collections.Generic; namespace Bit.App.Models.Api { @@ -12,5 +13,6 @@ namespace Bit.App.Models.Api public string RefreshToken { get; set; } [JsonProperty("token_type")] public string TokenType { get; set; } + public List TwoFactorProviders { get; set; } } } diff --git a/src/App/Pages/LoginPage.cs b/src/App/Pages/LoginPage.cs index c5dac853d..bbf685d47 100644 --- a/src/App/Pages/LoginPage.cs +++ b/src/App/Pages/LoginPage.cs @@ -197,6 +197,13 @@ namespace Bit.App.Pages return; } + if(response.Result.TwoFactorProviders != null && response.Result.TwoFactorProviders.Count > 0) + { + _googleAnalyticsService.TrackAppEvent("LoggedIn To Two-step"); + await Navigation.PushAsync(new LoginTwoFactorPage(request.Email, request.MasterPasswordHash, key)); + return; + } + _cryptoService.Key = key; _tokenService.Token = response.Result.AccessToken; _tokenService.RefreshToken = response.Result.RefreshToken; @@ -211,15 +218,8 @@ namespace Bit.App.Pages _pushNotification.Register(); } - if(false) // TODO: 2FA - { - await Navigation.PushAsync(new LoginTwoFactorPage()); - } - else - { - var task = Task.Run(async () => await _syncService.FullSyncAsync()); - Application.Current.MainPage = new MainPage(); - } + var task = Task.Run(async () => await _syncService.FullSyncAsync()); + Application.Current.MainPage = new MainPage(); } } } diff --git a/src/App/Pages/LoginTwoFactorPage.cs b/src/App/Pages/LoginTwoFactorPage.cs index 831380f37..781722057 100644 --- a/src/App/Pages/LoginTwoFactorPage.cs +++ b/src/App/Pages/LoginTwoFactorPage.cs @@ -8,6 +8,8 @@ using Xamarin.Forms; using XLabs.Ioc; using Acr.UserDialogs; using System.Threading.Tasks; +using Plugin.Settings.Abstractions; +using PushNotification.Plugin.Abstractions; namespace Bit.App.Pages { @@ -20,10 +22,20 @@ namespace Bit.App.Pages private IAppIdService _appIdService; private IUserDialogs _userDialogs; private ISyncService _syncService; + private ISettings _settings; + private IGoogleAnalyticsService _googleAnalyticsService; + private IPushNotification _pushNotification; + private readonly string _email; + private readonly string _masterPasswordHash; + private readonly byte[] _key; - public LoginTwoFactorPage() + public LoginTwoFactorPage(string email, string masterPasswordHash, byte[] key) : base(updateActivity: false) { + _email = email; + _masterPasswordHash = masterPasswordHash; + _key = key; + _cryptoService = Resolver.Resolve(); _authService = Resolver.Resolve(); _tokenService = Resolver.Resolve(); @@ -31,6 +43,9 @@ namespace Bit.App.Pages _appIdService = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _syncService = Resolver.Resolve(); + _settings = Resolver.Resolve(); + _googleAnalyticsService = Resolver.Resolve(); + _pushNotification = Resolver.Resolve(); Init(); } @@ -138,9 +153,10 @@ namespace Bit.App.Pages var request = new TokenRequest { - // TODO: username and pass from previous page + Email = _email, + MasterPasswordHash = _masterPasswordHash, Token = CodeCell.Entry.Text.Replace(" ", ""), - Provider = 0, + Provider = 0, // Authenticator app (only 1 provider for now, so hard coded) Device = new DeviceRequest(_appIdService, _deviceInfoService) }; @@ -153,10 +169,19 @@ namespace Bit.App.Pages 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.RefreshUserId(); + _googleAnalyticsService.TrackAppEvent("LoggedIn From Two-step"); + + if(Device.OS == TargetPlatform.Android) + { + _pushNotification.Register(); + } var task = Task.Run(async () => await _syncService.FullSyncAsync()); Application.Current.MainPage = new MainPage(); diff --git a/src/App/Repositories/ConnectApiRepository.cs b/src/App/Repositories/ConnectApiRepository.cs index 8b6769260..fb83e5001 100644 --- a/src/App/Repositories/ConnectApiRepository.cs +++ b/src/App/Repositories/ConnectApiRepository.cs @@ -6,6 +6,8 @@ using Bit.App.Models.Api; using Newtonsoft.Json; using Plugin.Connectivity.Abstractions; using System.Net; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; namespace Bit.App.Repositories { @@ -39,12 +41,22 @@ namespace Bit.App.Repositories try { var response = await client.SendAsync(requestMessage).ConfigureAwait(false); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if(!response.IsSuccessStatusCode) { + var errorResponse = JObject.Parse(responseContent); + if(errorResponse["TwoFactorProviders"] != null) + { + return ApiResult.Success(new TokenResponse + { + TwoFactorProviders = errorResponse["TwoFactorProviders"].ToObject>() + }, response.StatusCode); + } + return await HandleErrorAsync(response).ConfigureAwait(false); } - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var responseObj = JsonConvert.DeserializeObject(responseContent); return ApiResult.Success(responseObj, response.StatusCode); }