From 1db4c4fc8be176cc6d3214292842a7f8713709ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bispo?= Date: Mon, 3 Oct 2022 17:42:33 +0100 Subject: [PATCH] SG-687 Request time not updating (#2108) * [SG-687] request updates text with timer task and expires after 15 mins. * [SG-697] PR Fixes * [SG-687] Ran code format * [SG-687] PR Fixes * [SG-687] missed constant replacement * [SG-687] PR fixes --- .../Accounts/LoginPasswordlessPage.xaml.cs | 12 ++++++ .../Accounts/LoginPasswordlessViewModel.cs | 42 +++++++++++++++---- src/App/Utilities/TimerTask.cs | 36 +++++++++++----- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/App/Pages/Accounts/LoginPasswordlessPage.xaml.cs b/src/App/Pages/Accounts/LoginPasswordlessPage.xaml.cs index 5aa777a11..f6941a715 100644 --- a/src/App/Pages/Accounts/LoginPasswordlessPage.xaml.cs +++ b/src/App/Pages/Accounts/LoginPasswordlessPage.xaml.cs @@ -27,5 +27,17 @@ namespace Bit.App.Pages await Navigation.PopModalAsync(); } } + + protected override void OnAppearing() + { + base.OnAppearing(); + _vm.StartRequestTimeUpdater(); + } + + protected override void OnDisappearing() + { + base.OnDisappearing(); + _vm.StopRequestTimeUpdater(); + } } } diff --git a/src/App/Pages/Accounts/LoginPasswordlessViewModel.cs b/src/App/Pages/Accounts/LoginPasswordlessViewModel.cs index d1e8d0c28..a0c886d81 100644 --- a/src/App/Pages/Accounts/LoginPasswordlessViewModel.cs +++ b/src/App/Pages/Accounts/LoginPasswordlessViewModel.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Windows.Input; using Bit.App.Abstractions; @@ -8,6 +10,7 @@ using Bit.App.Utilities; using Bit.Core; using Bit.Core.Abstractions; using Bit.Core.Enums; +using Bit.Core.Services; using Bit.Core.Utilities; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.Forms; @@ -21,6 +24,10 @@ namespace Bit.App.Pages private IPlatformUtilsService _platformUtilsService; private ILogger _logger; private LoginPasswordlessDetails _resquest; + private CancellationTokenSource _requestTimeCts; + private Task _requestTimeTask; + + private const int REQUEST_TIME_UPDATE_PERIOD_IN_MINUTES = 5; public LoginPasswordlessViewModel() { @@ -63,6 +70,30 @@ namespace Bit.App.Pages } } + public void StopRequestTimeUpdater() + { + _requestTimeCts?.Cancel(); + _requestTimeCts?.Dispose(); + } + + public void StartRequestTimeUpdater() + { + _requestTimeCts?.Cancel(); + _requestTimeCts = new CancellationTokenSource(); + _requestTimeTask = new TimerTask(_logger, UpdateRequestTime, _requestTimeCts).RunPeriodic(TimeSpan.FromMinutes(REQUEST_TIME_UPDATE_PERIOD_IN_MINUTES)); + } + + private async Task UpdateRequestTime() + { + TriggerPropertyChanged(nameof(TimeOfRequestText)); + if (DateTime.UtcNow > LoginRequest?.RequestDate.ToUniversalTime().AddMinutes(Constants.PasswordlessNotificationTimeoutInMinutes)) + { + StopRequestTimeUpdater(); + await _platformUtilsService.ShowDialogAsync(AppResources.LoginRequestHasAlreadyExpired); + await Page.Navigation.PopModalAsync(); + } + } + private async Task PasswordlessLoginAsync(bool approveRequest) { if (LoginRequest.RequestDate.AddMinutes(Constants.PasswordlessNotificationTimeoutInMinutes) <= DateTime.Now) @@ -77,6 +108,8 @@ namespace Bit.App.Pages await _deviceActionService.HideLoadingAsync(); await Page.Navigation.PopModalAsync(); _platformUtilsService.ShowToast("info", null, approveRequest ? AppResources.LogInAccepted : AppResources.LogInDenied); + + StopRequestTimeUpdater(); } private string CreateRequestDate(DateTime? requestDate) @@ -86,17 +119,12 @@ namespace Bit.App.Pages return string.Empty; } - var minutesSinceRequest = requestDate.Value.ToUniversalTime().Minute - DateTime.UtcNow.Minute; - if (minutesSinceRequest < 5) + if (DateTime.UtcNow < requestDate.Value.ToUniversalTime().AddMinutes(REQUEST_TIME_UPDATE_PERIOD_IN_MINUTES)) { return AppResources.JustNow; } - if (minutesSinceRequest < 59) - { - return string.Format(AppResources.XMinutesAgo, minutesSinceRequest); - } - return requestDate.Value.ToShortTimeString(); + return string.Format(AppResources.XMinutesAgo, DateTime.UtcNow.Minute - requestDate.Value.ToUniversalTime().Minute); } private void HandleException(Exception ex) diff --git a/src/App/Utilities/TimerTask.cs b/src/App/Utilities/TimerTask.cs index a982d39b0..0288408ac 100644 --- a/src/App/Utilities/TimerTask.cs +++ b/src/App/Utilities/TimerTask.cs @@ -10,13 +10,21 @@ namespace Bit.App.Utilities { private readonly ILogger _logger; private readonly Action _action; - private readonly CancellationTokenSource _cancellationToken; + private readonly Func _actionTask; + private readonly CancellationTokenSource _cancellationTokenSource; - public TimerTask(ILogger logger, Action action, CancellationTokenSource cancellationToken) + public TimerTask(ILogger logger, Action action, CancellationTokenSource cancellationTokenSource) { _logger = logger; - _action = action ?? throw new ArgumentNullException(); - _cancellationToken = cancellationToken; + _action = action ?? throw new ArgumentNullException(nameof(action)); + _cancellationTokenSource = cancellationTokenSource; + } + + public TimerTask(ILogger logger, Func actionTask, CancellationTokenSource cancellationTokenSource) + { + _logger = logger; + _actionTask = actionTask ?? throw new ArgumentNullException(nameof(actionTask)); + _cancellationTokenSource = cancellationTokenSource; } public Task RunPeriodic(TimeSpan? interval = null) @@ -26,23 +34,31 @@ namespace Bit.App.Utilities { try { - while (!_cancellationToken.IsCancellationRequested) + while (!_cancellationTokenSource.IsCancellationRequested) { - await Device.InvokeOnMainThreadAsync(() => + await Device.InvokeOnMainThreadAsync(async () => { - if (!_cancellationToken.IsCancellationRequested) + if (!_cancellationTokenSource.IsCancellationRequested) { try { - _action(); + if (_action != null) + { + _action(); + } + else if (_actionTask != null) + { + await _actionTask(); + } } catch (Exception ex) { + _cancellationTokenSource?.Cancel(); _logger?.Exception(ex); } } }); - await Task.Delay(interval.Value, _cancellationToken.Token); + await Task.Delay(interval.Value, _cancellationTokenSource.Token); } } catch (TaskCanceledException) { } @@ -50,7 +66,7 @@ namespace Bit.App.Utilities { _logger?.Exception(ex); } - }, _cancellationToken.Token); + }, _cancellationTokenSource.Token); } } }