using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Bit.App.Abstractions; using Bit.App.Resources; using Bit.Core.Abstractions; using Bit.Core.Models.Response; using Bit.Core.Utilities; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.Forms; namespace Bit.App.Pages { public class LoginPasswordlessRequestsListViewModel : BaseViewModel { private readonly IAuthService _authService; private readonly IStateService _stateService; private readonly IDeviceActionService _deviceActionService; private readonly IPlatformUtilsService _platformUtilsService; private bool _isRefreshing; public LoginPasswordlessRequestsListViewModel() { _authService = ServiceContainer.Resolve(); _stateService = ServiceContainer.Resolve(); _deviceActionService = ServiceContainer.Resolve(); _platformUtilsService = ServiceContainer.Resolve(); PageTitle = AppResources.PendingLogInRequests; LoginRequests = new ObservableRangeCollection(); AnswerRequestCommand = new AsyncCommand(PasswordlessLoginAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false); DeclineAllRequestsCommand = new AsyncCommand(DeclineAllRequestsAsync, onException: ex => HandleException(ex), allowsMultipleExecutions: false); RefreshCommand = new Command(async () => await RefreshAsync()); } public ICommand RefreshCommand { get; } public AsyncCommand AnswerRequestCommand { get; } public AsyncCommand DeclineAllRequestsCommand { get; } public ObservableRangeCollection LoginRequests { get; } public bool IsRefreshing { get => _isRefreshing; set => SetProperty(ref _isRefreshing, value); } public async Task RefreshAsync() { try { IsRefreshing = true; LoginRequests.ReplaceRange(await _authService.GetActivePasswordlessLoginRequestsAsync()); if (!LoginRequests.Any()) { Page.Navigation.PopModalAsync().FireAndForget(); } } catch (Exception ex) { HandleException(ex); } finally { IsRefreshing = false; } } private async Task PasswordlessLoginAsync(PasswordlessLoginResponse request) { if (request.IsExpired) { await _platformUtilsService.ShowDialogAsync(AppResources.LoginRequestHasAlreadyExpired); await Page.Navigation.PopModalAsync(); return; } var loginRequestData = await _authService.GetPasswordlessLoginRequestByIdAsync(request.Id); if (loginRequestData.IsAnswered) { await _platformUtilsService.ShowDialogAsync(AppResources.ThisRequestIsNoLongerValid); return; } var page = new LoginPasswordlessPage(new LoginPasswordlessDetails() { PubKey = loginRequestData.PublicKey, Id = loginRequestData.Id, IpAddress = loginRequestData.RequestIpAddress, Email = await _stateService.GetEmailAsync(), FingerprintPhrase = loginRequestData.RequestFingerprint, RequestDate = loginRequestData.CreationDate, DeviceType = loginRequestData.RequestDeviceType, Origin = loginRequestData.Origin }); await Device.InvokeOnMainThreadAsync(() => Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page))); } private async Task DeclineAllRequestsAsync() { try { if (!await _platformUtilsService.ShowDialogAsync(AppResources.AreYouSureYouWantToDeclineAllPendingLogInRequests, null, AppResources.Yes, AppResources.No)) { return; } await _deviceActionService.ShowLoadingAsync(AppResources.Loading); var taskList = new List(); foreach (var request in LoginRequests) { taskList.Add(_authService.PasswordlessLoginAsync(request.Id, request.PublicKey, false)); } await Task.WhenAll(taskList); await _deviceActionService.HideLoadingAsync(); await RefreshAsync(); _platformUtilsService.ShowToast("info", null, AppResources.RequestsDeclined); } catch (Exception ex) { HandleException(ex); RefreshAsync().FireAndForget(); } } } }