mirror of
https://github.com/bitwarden/mobile
synced 2026-01-05 01:53:17 +00:00
PM-5154 [Passkeys iOS] Refactored and added cipher selection for passkey creation on autofill search.
This commit is contained in:
10
src/iOS.Autofill/ILoginListViewController.cs
Normal file
10
src/iOS.Autofill/ILoginListViewController.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Bit.iOS.Autofill.Models;
|
||||
|
||||
namespace Bit.iOS.Autofill
|
||||
{
|
||||
public interface ILoginListViewController
|
||||
{
|
||||
Context Context { get; }
|
||||
CredentialProviderViewController CPViewController { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
@@ -19,7 +18,7 @@ using UIKit;
|
||||
|
||||
namespace Bit.iOS.Autofill
|
||||
{
|
||||
public partial class LoginListViewController : ExtendedUIViewController
|
||||
public partial class LoginListViewController : ExtendedUIViewController, ILoginListViewController
|
||||
{
|
||||
internal const string HEADER_SECTION_IDENTIFIER = "headerSectionId";
|
||||
|
||||
@@ -30,12 +29,10 @@ namespace Bit.iOS.Autofill
|
||||
: base(handle)
|
||||
{
|
||||
DismissModalAction = Cancel;
|
||||
PasswordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
||||
}
|
||||
|
||||
public Context Context { get; set; }
|
||||
public CredentialProviderViewController CPViewController { get; set; }
|
||||
public IPasswordRepromptService PasswordRepromptService { get; private set; }
|
||||
|
||||
AccountSwitchingOverlayView _accountSwitchingOverlayView;
|
||||
AccountSwitchingOverlayHelper _accountSwitchingOverlayHelper;
|
||||
@@ -254,20 +251,14 @@ namespace Bit.iOS.Autofill
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public class TableSource : ExtensionTableSource
|
||||
public class TableSource : BaseLoginListTableSource<LoginListViewController>
|
||||
{
|
||||
private readonly LoginListViewController _controller;
|
||||
|
||||
private readonly LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
|
||||
private readonly LazyResolve<IPasswordRepromptService> _passwordRepromptService = new LazyResolve<IPasswordRepromptService>();
|
||||
|
||||
public TableSource(LoginListViewController controller)
|
||||
: base(controller.Context, controller)
|
||||
: base(controller)
|
||||
{
|
||||
_controller = controller;
|
||||
}
|
||||
|
||||
private Context Context => (Context)_context;
|
||||
protected override string LoginAddSegue => SegueConstants.ADD_LOGIN;
|
||||
|
||||
public override async Task LoadAsync(bool urlFilter = true, string searchFilter = null)
|
||||
{
|
||||
@@ -277,7 +268,7 @@ namespace Bit.iOS.Autofill
|
||||
|
||||
if (Context.IsCreatingPasskey && !Items.Any())
|
||||
{
|
||||
_controller?.OnEmptyList();
|
||||
Controller?.OnEmptyList();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -316,62 +307,6 @@ namespace Bit.iOS.Autofill
|
||||
|
||||
return base.RowsInSection(tableview, section);
|
||||
}
|
||||
|
||||
public async override void RowSelected(UITableView tableView, NSIndexPath indexPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Context.IsCreatingPasskey)
|
||||
{
|
||||
await SelectRowForPasskeyCreationAsync(tableView, indexPath);
|
||||
return;
|
||||
}
|
||||
|
||||
await AutofillHelpers.TableRowSelectedAsync(tableView, indexPath, this,
|
||||
_controller.CPViewController, _controller, _controller.PasswordRepromptService, "loginAddSegue");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SelectRowForPasskeyCreationAsync(UITableView tableView, NSIndexPath indexPath)
|
||||
{
|
||||
tableView.DeselectRow(indexPath, true);
|
||||
tableView.EndEditing(true);
|
||||
|
||||
var item = Items.ElementAt(indexPath.Row);
|
||||
if (item is null)
|
||||
{
|
||||
await _platformUtilsService.Value.ShowDialogAsync(AppResources.GenericErrorMessage, AppResources.AnErrorHasOccurred);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.CipherView.Login.HasFido2Credentials
|
||||
&&
|
||||
!await _platformUtilsService.Value.ShowDialogAsync(
|
||||
AppResources.ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey,
|
||||
AppResources.OverwritePasskey,
|
||||
AppResources.Yes,
|
||||
AppResources.No))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await _passwordRepromptService.Value.PromptAndCheckPasswordIfNeededAsync(item.Reprompt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Check user verification
|
||||
|
||||
Context.ConfirmNewCredentialTcs.SetResult(new Fido2ConfirmNewCredentialResult
|
||||
{
|
||||
CipherId = item.Id,
|
||||
UserVerified = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,17 @@ using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.iOS.Autofill
|
||||
{
|
||||
public partial class LoginSearchViewController : ExtendedUITableViewController
|
||||
public partial class LoginSearchViewController : ExtendedUITableViewController, ILoginListViewController
|
||||
{
|
||||
public LoginSearchViewController(IntPtr handle)
|
||||
: base(handle)
|
||||
{
|
||||
DismissModalAction = Cancel;
|
||||
PasswordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
||||
}
|
||||
|
||||
public Context Context { get; set; }
|
||||
public CredentialProviderViewController CPViewController { get; set; }
|
||||
public bool FromList { get; set; }
|
||||
public IPasswordRepromptService PasswordRepromptService { get; private set; }
|
||||
|
||||
public async override void ViewDidLoad()
|
||||
{
|
||||
@@ -61,13 +59,13 @@ namespace Bit.iOS.Autofill
|
||||
}
|
||||
else
|
||||
{
|
||||
CPViewController.CompleteRequest();
|
||||
CPViewController.CancelRequest(AuthenticationServices.ASExtensionErrorCode.UserCanceled);
|
||||
}
|
||||
}
|
||||
|
||||
partial void AddBarButton_Activated(UIBarButtonItem sender)
|
||||
{
|
||||
PerformSegue("loginAddFromSearchSegue", this);
|
||||
PerformSegue(SegueConstants.ADD_LOGIN_FROM_SEARCH, this);
|
||||
}
|
||||
|
||||
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
|
||||
@@ -93,24 +91,14 @@ namespace Bit.iOS.Autofill
|
||||
});
|
||||
}
|
||||
|
||||
public class TableSource : ExtensionTableSource
|
||||
public class TableSource : BaseLoginListTableSource<LoginSearchViewController>
|
||||
{
|
||||
private Context _context;
|
||||
private LoginSearchViewController _controller;
|
||||
|
||||
public TableSource(LoginSearchViewController controller)
|
||||
: base(controller.Context, controller)
|
||||
: base(controller)
|
||||
{
|
||||
_context = controller.Context;
|
||||
_controller = controller;
|
||||
}
|
||||
|
||||
public async override void RowSelected(UITableView tableView, NSIndexPath indexPath)
|
||||
{
|
||||
await AutofillHelpers.TableRowSelectedAsync(tableView, indexPath, this,
|
||||
_controller.CPViewController, _controller, _controller.PasswordRepromptService,
|
||||
"loginAddFromSearchSegue");
|
||||
}
|
||||
protected override string LoginAddSegue => SegueConstants.ADD_LOGIN_FROM_SEARCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
public const string SETUP = "setupSegue";
|
||||
public const string ADD_LOGIN = "loginAddSegue";
|
||||
public const string LOGIN_SEARCH_FROM_LIST = "loginSearchFromListSegue";
|
||||
public const string ADD_LOGIN_FROM_SEARCH = "loginAddFromSearchSegue";
|
||||
}
|
||||
}
|
||||
|
||||
91
src/iOS.Autofill/Utilities/BaseLoginListTableSource.cs
Normal file
91
src/iOS.Autofill/Utilities/BaseLoginListTableSource.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.iOS.Autofill.Models;
|
||||
using Bit.iOS.Core.Views;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Autofill.Utilities
|
||||
{
|
||||
public abstract class BaseLoginListTableSource<T> : ExtensionTableSource
|
||||
where T : UIViewController, ILoginListViewController
|
||||
{
|
||||
private IPasswordRepromptService _passwordRepromptService;
|
||||
private readonly LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
|
||||
|
||||
public BaseLoginListTableSource(T controller)
|
||||
: base(controller.Context, controller)
|
||||
{
|
||||
_controller = controller;
|
||||
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>();
|
||||
}
|
||||
|
||||
protected Context Context => (Context)_context;
|
||||
protected T Controller => (T)_controller;
|
||||
|
||||
protected abstract string LoginAddSegue { get; }
|
||||
|
||||
public async override void RowSelected(UITableView tableView, NSIndexPath indexPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Context.IsCreatingPasskey)
|
||||
{
|
||||
await SelectRowForPasskeyCreationAsync(tableView, indexPath);
|
||||
return;
|
||||
}
|
||||
|
||||
await AutofillHelpers.TableRowSelectedAsync(tableView, indexPath, this,
|
||||
Controller.CPViewController, Controller, _passwordRepromptService, LoginAddSegue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SelectRowForPasskeyCreationAsync(UITableView tableView, NSIndexPath indexPath)
|
||||
{
|
||||
tableView.DeselectRow(indexPath, true);
|
||||
tableView.EndEditing(true);
|
||||
|
||||
var item = Items.ElementAt(indexPath.Row);
|
||||
if (item is null)
|
||||
{
|
||||
await _platformUtilsService.Value.ShowDialogAsync(AppResources.GenericErrorMessage, AppResources.AnErrorHasOccurred);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.CipherView.Login.HasFido2Credentials
|
||||
&&
|
||||
!await _platformUtilsService.Value.ShowDialogAsync(
|
||||
AppResources.ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey,
|
||||
AppResources.OverwritePasskey,
|
||||
AppResources.Yes,
|
||||
AppResources.No))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await _passwordRepromptService.PromptAndCheckPasswordIfNeededAsync(item.Reprompt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Check user verification
|
||||
|
||||
Context.ConfirmNewCredentialTcs.SetResult(new Fido2ConfirmNewCredentialResult
|
||||
{
|
||||
CipherId = item.Id,
|
||||
UserVerified = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@
|
||||
<Compile Include="SegueConstants.cs" />
|
||||
<Compile Include="ColorConstants.cs" />
|
||||
<Compile Include="ListItems\HeaderItemView.cs" />
|
||||
<Compile Include="Utilities\BaseLoginListTableSource.cs" />
|
||||
<Compile Include="ILoginListViewController.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\check.png" />
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Bit.iOS.Core.Views
|
||||
protected IStateService _stateService;
|
||||
protected ISearchService _searchService;
|
||||
protected AppExtensionContext _context;
|
||||
private UIViewController _controller;
|
||||
protected UIViewController _controller;
|
||||
|
||||
public ExtensionTableSource(AppExtensionContext context, UIViewController controller)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user