mirror of
https://github.com/bitwarden/mobile
synced 2025-12-15 15:53:44 +00:00
[SG-834] Mobile pending login requests management screen (#2281)
* Bootstrap new classes for settings list * [SG-834] Add new method GetActivePasswordlessLoginRequestsAsync to AuthService * [SG-834] Add generic handle exception method to BaseViewModel * [SG-834] Add request verification to settings entry * [SG-834] Add text resources * [SG-834] Update view and viewmodel * [SG-834] Remove unnecessary property assignment * [SG-834] removed logger resolve
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
using Xamarin.Forms;
|
using System.Linq;
|
||||||
|
using Xamarin.CommunityToolkit.Converters;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
@@ -6,4 +8,13 @@ namespace Bit.App.Controls
|
|||||||
{
|
{
|
||||||
public string ExtraDataForLogging { get; set; }
|
public string ExtraDataForLogging { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SelectionChangedEventArgsConverter : BaseNullableConverterOneWay<SelectionChangedEventArgs, object>
|
||||||
|
{
|
||||||
|
public override object? ConvertFrom(SelectionChangedEventArgs? value)
|
||||||
|
{
|
||||||
|
return value?.CurrentSelection.FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
var loginRequestData = await _authService.GetPasswordlessLoginRequestByIdAsync(LoginRequest.Id);
|
var loginRequestData = await _authService.GetPasswordlessLoginRequestByIdAsync(LoginRequest.Id);
|
||||||
if (loginRequestData.RequestApproved.HasValue && loginRequestData.ResponseDate.HasValue)
|
if (loginRequestData.IsAnswered)
|
||||||
{
|
{
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.ThisRequestIsNoLongerValid);
|
await _platformUtilsService.ShowDialogAsync(AppResources.ThisRequestIsNoLongerValid);
|
||||||
await Page.Navigation.PopModalAsync();
|
await Page.Navigation.PopModalAsync();
|
||||||
|
|||||||
107
src/App/Pages/Settings/LoginPasswordlessRequestsListPage.xaml
Normal file
107
src/App/Pages/Settings/LoginPasswordlessRequestsListPage.xaml
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<pages:BaseContentPage
|
||||||
|
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
|
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
|
||||||
|
x:Class="Bit.App.Pages.LoginPasswordlessRequestsListPage"
|
||||||
|
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||||
|
x:DataType="pages:LoginPasswordlessRequestsListViewModel"
|
||||||
|
xmlns:models="clr-namespace:Bit.Core.Models.Response;assembly=BitwardenCore"
|
||||||
|
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
|
||||||
|
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||||
|
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||||
|
Title="{Binding PageTitle}">
|
||||||
|
|
||||||
|
<ContentPage.BindingContext>
|
||||||
|
<pages:LoginPasswordlessRequestsListViewModel />
|
||||||
|
</ContentPage.BindingContext>
|
||||||
|
|
||||||
|
<ContentPage.ToolbarItems>
|
||||||
|
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
|
||||||
|
</ContentPage.ToolbarItems>
|
||||||
|
|
||||||
|
<ContentPage.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<u:DateTimeConverter x:Key="dateTime" />
|
||||||
|
<xct:ItemSelectedEventArgsConverter x:Key="ItemSelectedEventArgsConverter" />
|
||||||
|
<controls:SelectionChangedEventArgsConverter x:Key="SelectionChangedEventArgsConverter" />
|
||||||
|
<DataTemplate
|
||||||
|
x:Key="loginRequestTemplate"
|
||||||
|
x:DataType="models:PasswordlessLoginResponse">
|
||||||
|
<Grid
|
||||||
|
Padding="10, 0"
|
||||||
|
RowSpacing="0"
|
||||||
|
RowDefinitions="*, Auto, *, 10"
|
||||||
|
ColumnDefinitions="*, *">
|
||||||
|
<Label
|
||||||
|
Text="{u:I18n FingerprintPhrase}"
|
||||||
|
FontSize="Small"
|
||||||
|
Padding="0, 10, 0 ,0"
|
||||||
|
FontAttributes="Bold"/>
|
||||||
|
<controls:MonoLabel
|
||||||
|
FormattedText="{Binding RequestFingerprint}"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
FontSize="Small"
|
||||||
|
Padding="0, 5, 0, 10"
|
||||||
|
VerticalTextAlignment="Center"
|
||||||
|
TextColor="{DynamicResource FingerprintPhrase}"/>
|
||||||
|
<Label
|
||||||
|
Grid.Row="2"
|
||||||
|
HorizontalOptions="Start"
|
||||||
|
HorizontalTextAlignment="Start"
|
||||||
|
Text="{Binding RequestDeviceType}"
|
||||||
|
StyleClass="list-header-sub" />
|
||||||
|
<Label
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalOptions="End"
|
||||||
|
HorizontalTextAlignment="End"
|
||||||
|
Text="{Binding CreationDate, Converter={StaticResource dateTime}}"
|
||||||
|
StyleClass="list-header-sub" />
|
||||||
|
<BoxView
|
||||||
|
StyleClass="list-section-separator-top, list-section-separator-top-platform"
|
||||||
|
VerticalOptions="End"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.ColumnSpan="2"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<StackLayout
|
||||||
|
x:Key="mainLayout"
|
||||||
|
x:Name="_mainLayout"
|
||||||
|
Padding="0, 10">
|
||||||
|
<RefreshView
|
||||||
|
IsRefreshing="{Binding IsRefreshing}"
|
||||||
|
Command="{Binding RefreshCommand}"
|
||||||
|
VerticalOptions="FillAndExpand"
|
||||||
|
BackgroundColor="{DynamicResource BackgroundColor}">
|
||||||
|
<controls:ExtendedCollectionView
|
||||||
|
ItemsSource="{Binding LoginRequests}"
|
||||||
|
ItemTemplate="{StaticResource loginRequestTemplate}"
|
||||||
|
SelectionMode="Single"
|
||||||
|
ExtraDataForLogging="Login requests page" >
|
||||||
|
<controls:ExtendedCollectionView.Behaviors>
|
||||||
|
<xct:EventToCommandBehavior
|
||||||
|
EventName="SelectionChanged"
|
||||||
|
Command="{Binding AnswerRequestCommand}"
|
||||||
|
EventArgsConverter="{StaticResource SelectionChangedEventArgsConverter}" />
|
||||||
|
</controls:ExtendedCollectionView.Behaviors>
|
||||||
|
</controls:ExtendedCollectionView>
|
||||||
|
</RefreshView>
|
||||||
|
<controls:IconLabelButton
|
||||||
|
VerticalOptions="End"
|
||||||
|
Margin="10,0"
|
||||||
|
Icon="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
|
||||||
|
Label="{u:I18n DeclineAllRequests}"
|
||||||
|
ButtonCommand="{Binding DeclineAllRequestsCommand}"/>
|
||||||
|
</StackLayout>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</ContentPage.Resources>
|
||||||
|
|
||||||
|
<ContentView
|
||||||
|
x:Name="_mainContent">
|
||||||
|
</ContentView>
|
||||||
|
|
||||||
|
</pages:BaseContentPage>
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Models.Response;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public partial class LoginPasswordlessRequestsListPage : BaseContentPage
|
||||||
|
{
|
||||||
|
private LoginPasswordlessRequestsListViewModel _vm;
|
||||||
|
|
||||||
|
public LoginPasswordlessRequestsListPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
SetActivityIndicator(_mainContent);
|
||||||
|
_vm = BindingContext as LoginPasswordlessRequestsListViewModel;
|
||||||
|
_vm.Page = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async void OnAppearing()
|
||||||
|
{
|
||||||
|
base.OnAppearing();
|
||||||
|
await LoadOnAppearedAsync(_mainLayout, false, _vm.RefreshAsync, _mainContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Close_Clicked(object sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
if (DoOnce())
|
||||||
|
{
|
||||||
|
await Navigation.PopModalAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
139
src/App/Pages/Settings/LoginPasswordlessRequestsListViewModel.cs
Normal file
139
src/App/Pages/Settings/LoginPasswordlessRequestsListViewModel.cs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
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<IAuthService>();
|
||||||
|
_stateService = ServiceContainer.Resolve<IStateService>();
|
||||||
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>();
|
||||||
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
|
||||||
|
|
||||||
|
PageTitle = AppResources.PendingLogInRequests;
|
||||||
|
LoginRequests = new ObservableRangeCollection<PasswordlessLoginResponse>();
|
||||||
|
|
||||||
|
AnswerRequestCommand = new AsyncCommand<PasswordlessLoginResponse>(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<PasswordlessLoginResponse> AnswerRequestCommand { get; }
|
||||||
|
|
||||||
|
public AsyncCommand DeclineAllRequestsCommand { get; }
|
||||||
|
|
||||||
|
public ObservableRangeCollection<PasswordlessLoginResponse> 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<Task>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ using Bit.Core.Abstractions;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
|
using Bit.Core.Models.Response;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
@@ -35,6 +36,7 @@ namespace Bit.App.Pages
|
|||||||
private readonly IClipboardService _clipboardService;
|
private readonly IClipboardService _clipboardService;
|
||||||
private readonly ILogger _loggerService;
|
private readonly ILogger _loggerService;
|
||||||
private readonly IPushNotificationService _pushNotificationService;
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
|
private readonly IAuthService _authService;
|
||||||
private readonly IWatchDeviceService _watchDeviceService;
|
private readonly IWatchDeviceService _watchDeviceService;
|
||||||
private const int CustomVaultTimeoutValue = -100;
|
private const int CustomVaultTimeoutValue = -100;
|
||||||
|
|
||||||
@@ -49,7 +51,6 @@ namespace Bit.App.Pages
|
|||||||
private bool _reportLoggingEnabled;
|
private bool _reportLoggingEnabled;
|
||||||
private bool _approvePasswordlessLoginRequests;
|
private bool _approvePasswordlessLoginRequests;
|
||||||
private bool _shouldConnectToWatch;
|
private bool _shouldConnectToWatch;
|
||||||
|
|
||||||
private List<KeyValuePair<string, int?>> _vaultTimeouts =
|
private List<KeyValuePair<string, int?>> _vaultTimeouts =
|
||||||
new List<KeyValuePair<string, int?>>
|
new List<KeyValuePair<string, int?>>
|
||||||
{
|
{
|
||||||
@@ -92,8 +93,8 @@ namespace Bit.App.Pages
|
|||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||||
_loggerService = ServiceContainer.Resolve<ILogger>("logger");
|
_loggerService = ServiceContainer.Resolve<ILogger>("logger");
|
||||||
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
||||||
|
_authService = ServiceContainer.Resolve<IAuthService>();
|
||||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||||
|
|
||||||
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
|
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
|
||||||
PageTitle = AppResources.Settings;
|
PageTitle = AppResources.Settings;
|
||||||
|
|
||||||
@@ -144,7 +145,6 @@ namespace Bit.App.Pages
|
|||||||
!await _keyConnectorService.GetUsesKeyConnector();
|
!await _keyConnectorService.GetUsesKeyConnector();
|
||||||
_reportLoggingEnabled = await _loggerService.IsEnabled();
|
_reportLoggingEnabled = await _loggerService.IsEnabled();
|
||||||
_approvePasswordlessLoginRequests = await _stateService.GetApprovePasswordlessLoginsAsync();
|
_approvePasswordlessLoginRequests = await _stateService.GetApprovePasswordlessLoginsAsync();
|
||||||
|
|
||||||
_shouldConnectToWatch = await _stateService.GetShouldConnectToWatchAsync();
|
_shouldConnectToWatch = await _stateService.GetShouldConnectToWatchAsync();
|
||||||
|
|
||||||
BuildList();
|
BuildList();
|
||||||
@@ -563,6 +563,14 @@ namespace Bit.App.Pages
|
|||||||
ExecuteAsync = () => TwoStepAsync()
|
ExecuteAsync = () => TwoStepAsync()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (_approvePasswordlessLoginRequests)
|
||||||
|
{
|
||||||
|
manageItems.Add(new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.PendingLogInRequests,
|
||||||
|
ExecuteAsync = () => PendingLoginRequestsAsync()
|
||||||
|
});
|
||||||
|
}
|
||||||
if (_supportsBiometric || _biometric)
|
if (_supportsBiometric || _biometric)
|
||||||
{
|
{
|
||||||
var biometricName = AppResources.Biometrics;
|
var biometricName = AppResources.Biometrics;
|
||||||
@@ -754,6 +762,25 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task PendingLoginRequestsAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var requests = await _authService.GetActivePasswordlessLoginRequestsAsync();
|
||||||
|
if (requests == null || !requests.Any())
|
||||||
|
{
|
||||||
|
_platformUtilsService.ShowToast("info", null, AppResources.NoPendingRequests);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())).FireAndForget();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HandleException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool IncludeLinksWithSubscriptionInfo()
|
private bool IncludeLinksWithSubscriptionInfo()
|
||||||
{
|
{
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
if (Device.RuntimePlatform == Device.iOS)
|
||||||
|
|||||||
45
src/App/Resources/AppResources.Designer.cs
generated
45
src/App/Resources/AppResources.Designer.cs
generated
@@ -562,6 +562,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Are you sure you want to decline all pending login requests?.
|
||||||
|
/// </summary>
|
||||||
|
public static string AreYouSureYouWantToDeclineAllPendingLogInRequests {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AreYouSureYouWantToDeclineAllPendingLogInRequests", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Are you sure you want to turn on screen capture?.
|
/// Looks up a localized string similar to Are you sure you want to turn on screen capture?.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1759,6 +1768,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Decline all requests.
|
||||||
|
/// </summary>
|
||||||
|
public static string DeclineAllRequests {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("DeclineAllRequests", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Default.
|
/// Looks up a localized string similar to Default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -4283,6 +4301,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to No pending requests.
|
||||||
|
/// </summary>
|
||||||
|
public static string NoPendingRequests {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NoPendingRequests", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Nord.
|
/// Looks up a localized string similar to Nord.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -4770,6 +4797,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Pending login requests.
|
||||||
|
/// </summary>
|
||||||
|
public static string PendingLogInRequests {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("PendingLogInRequests", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to An organization policy is affecting your ownership options..
|
/// Looks up a localized string similar to An organization policy is affecting your ownership options..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5122,6 +5158,15 @@ namespace Bit.App.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Requests declined.
|
||||||
|
/// </summary>
|
||||||
|
public static string RequestsDeclined {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("RequestsDeclined", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Resend code.
|
/// Looks up a localized string similar to Resend code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2523,6 +2523,21 @@ Do you want to switch to this account?</value>
|
|||||||
<data name="ThisRequestIsNoLongerValid" xml:space="preserve">
|
<data name="ThisRequestIsNoLongerValid" xml:space="preserve">
|
||||||
<value>This request is no longer valid</value>
|
<value>This request is no longer valid</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PendingLogInRequests" xml:space="preserve">
|
||||||
|
<value>Pending login requests</value>
|
||||||
|
</data>
|
||||||
|
<data name="DeclineAllRequests" xml:space="preserve">
|
||||||
|
<value>Decline all requests</value>
|
||||||
|
</data>
|
||||||
|
<data name="AreYouSureYouWantToDeclineAllPendingLogInRequests" xml:space="preserve">
|
||||||
|
<value>Are you sure you want to decline all pending login requests?</value>
|
||||||
|
</data>
|
||||||
|
<data name="RequestsDeclined" xml:space="preserve">
|
||||||
|
<value>Requests declined</value>
|
||||||
|
</data>
|
||||||
|
<data name="NoPendingRequests" xml:space="preserve">
|
||||||
|
<value>No pending requests</value>
|
||||||
|
</data>
|
||||||
<data name="EnableCamerPermissionToUseTheScanner" xml:space="preserve">
|
<data name="EnableCamerPermissionToUseTheScanner" xml:space="preserve">
|
||||||
<value>Enable camera permission to use the scanner</value>
|
<value>Enable camera permission to use the scanner</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<AuthResult> LogInPasswordlessAsync(string email, string accessCode, string authRequestId, byte[] decryptionKey, string userKeyCiphered, string localHashedPasswordCiphered);
|
Task<AuthResult> LogInPasswordlessAsync(string email, string accessCode, string authRequestId, byte[] decryptionKey, string userKeyCiphered, string localHashedPasswordCiphered);
|
||||||
|
|
||||||
Task<List<PasswordlessLoginResponse>> GetPasswordlessLoginRequestsAsync();
|
Task<List<PasswordlessLoginResponse>> GetPasswordlessLoginRequestsAsync();
|
||||||
|
Task<List<PasswordlessLoginResponse>> GetActivePasswordlessLoginRequestsAsync();
|
||||||
Task<PasswordlessLoginResponse> GetPasswordlessLoginRequestByIdAsync(string id);
|
Task<PasswordlessLoginResponse> GetPasswordlessLoginRequestByIdAsync(string id);
|
||||||
Task<PasswordlessLoginResponse> GetPasswordlessLoginResponseAsync(string id, string accessCode);
|
Task<PasswordlessLoginResponse> GetPasswordlessLoginResponseAsync(string id, string accessCode);
|
||||||
Task<PasswordlessLoginResponse> PasswordlessLoginAsync(string id, string pubKey, bool requestApproved);
|
Task<PasswordlessLoginResponse> PasswordlessLoginAsync(string id, string pubKey, bool requestApproved);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
@@ -494,6 +495,12 @@ namespace Bit.Core.Services
|
|||||||
return await _apiService.GetAuthRequestAsync();
|
return await _apiService.GetAuthRequestAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<PasswordlessLoginResponse>> GetActivePasswordlessLoginRequestsAsync()
|
||||||
|
{
|
||||||
|
var requests = await GetPasswordlessLoginRequestsAsync();
|
||||||
|
return requests.Where(r => !r.IsAnswered && !r.IsExpired).OrderByDescending(r => r.CreationDate).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<PasswordlessLoginResponse> GetPasswordlessLoginRequestByIdAsync(string id)
|
public async Task<PasswordlessLoginResponse> GetPasswordlessLoginRequestByIdAsync(string id)
|
||||||
{
|
{
|
||||||
return await _apiService.GetAuthRequestAsync(id);
|
return await _apiService.GetAuthRequestAsync(id);
|
||||||
|
|||||||
Reference in New Issue
Block a user