1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-12 06:13:21 +00:00

SG-210 Account Switching in Autofill (iOS) (#1909)

* SG-210 Set up account switching on Autofill iOS

* SG-210 Fix refresh after sync on autofill ciphers, also added account switching on lock view on autofill. Also fix possible crash when scrolling when no items were displayed and also fixed navigation when login in on an automatically logged out account.

* SG-210 Added reference on iOS.Core project

* Fix formatting on AccountManager

* SG-210 Fix background color for dark theme
This commit is contained in:
Federico Maccaroni
2022-06-08 14:24:01 -03:00
committed by GitHub
parent 88b406544b
commit fba407f3b6
24 changed files with 1500 additions and 417 deletions

View File

@@ -1,27 +1,32 @@
using AuthenticationServices;
using System;
using System.Threading.Tasks;
using AuthenticationServices;
using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Pages;
using Bit.App.Utilities;
using Bit.App.Utilities.AccountManagement;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Bit.iOS.Autofill.Models;
using Bit.iOS.Core.Utilities;
using Foundation;
using System;
using System.Threading.Tasks;
using Bit.App.Pages;
using UIKit;
using Xamarin.Forms;
using Bit.App.Utilities;
using Bit.App.Models;
using Bit.iOS.Core.Views;
using CoreNFC;
using Foundation;
using UIKit;
using Xamarin.Forms;
namespace Bit.iOS.Autofill
{
public partial class CredentialProviderViewController : ASCredentialProviderViewController
public partial class CredentialProviderViewController : ASCredentialProviderViewController, IAccountsManagerHost
{
private Context _context;
private NFCNdefReaderSession _nfcSession = null;
private Core.NFCReaderDelegate _nfcDelegate = null;
private IAccountsManager _accountsManager;
private readonly LazyResolve<IStateService> _stateService = new LazyResolve<IStateService>("stateService");
public CredentialProviderViewController(IntPtr handle)
: base(handle)
@@ -56,7 +61,7 @@ namespace Bit.iOS.Autofill
}
if (!await IsAuthed())
{
LaunchHomePage();
await _accountsManager.NavigateOnAccountChangeAsync(false);
}
else if (await IsLocked())
{
@@ -78,9 +83,8 @@ namespace Bit.iOS.Autofill
public override async void ProvideCredentialWithoutUserInteraction(ASPasswordCredentialIdentity credentialIdentity)
{
InitAppIfNeeded();
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
await stateService.SetPasswordRepromptAutofillAsync(false);
await stateService.SetPasswordVerifiedAutofillAsync(false);
await _stateService.Value.SetPasswordRepromptAutofillAsync(false);
await _stateService.Value.SetPasswordVerifiedAutofillAsync(false);
if (!await IsAuthed() || await IsLocked())
{
var err = new NSError(new NSString("ASExtensionErrorDomain"),
@@ -97,7 +101,7 @@ namespace Bit.iOS.Autofill
InitAppIfNeeded();
if (!await IsAuthed())
{
LaunchHomePage();
await _accountsManager.NavigateOnAccountChangeAsync(false);
return;
}
_context.CredentialIdentity = credentialIdentity;
@@ -110,7 +114,7 @@ namespace Bit.iOS.Autofill
_context.Configuring = true;
if (!await IsAuthed())
{
LaunchHomePage();
await _accountsManager.NavigateOnAccountChangeAsync(false);
return;
}
CheckLock(() => PerformSegue("setupSegue", this));
@@ -229,7 +233,6 @@ namespace Bit.iOS.Autofill
return;
}
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var decCipher = await cipher.DecryptAsync();
if (decCipher.Reprompt != Bit.Core.Enums.CipherRepromptType.None)
{
@@ -237,13 +240,13 @@ namespace Bit.iOS.Autofill
// already verified the password.
if (!userInteraction)
{
await stateService.SetPasswordRepromptAutofillAsync(true);
await _stateService.Value.SetPasswordRepromptAutofillAsync(true);
var err = new NSError(new NSString("ASExtensionErrorDomain"),
Convert.ToInt32(ASExtensionErrorCode.UserInteractionRequired), null);
ExtensionContext?.CancelRequest(err);
return;
}
else if (!await stateService.GetPasswordVerifiedAutofillAsync())
else if (!await _stateService.Value.GetPasswordVerifiedAutofillAsync())
{
// Add a timeout to resolve keyboard not always showing up.
await Task.Delay(250);
@@ -258,10 +261,10 @@ namespace Bit.iOS.Autofill
}
}
string totpCode = null;
var disableTotpCopy = await stateService.GetDisableAutoTotpCopyAsync();
var disableTotpCopy = await _stateService.Value.GetDisableAutoTotpCopyAsync();
if (!disableTotpCopy.GetValueOrDefault(false))
{
var canAccessPremiumAsync = await stateService.CanAccessPremiumAsync();
var canAccessPremiumAsync = await _stateService.Value.CanAccessPremiumAsync();
if (!string.IsNullOrWhiteSpace(decCipher.Login.Totp) &&
(canAccessPremiumAsync || cipher.OrganizationUseTotp))
{
@@ -275,8 +278,7 @@ namespace Bit.iOS.Autofill
private async void CheckLock(Action notLockedAction)
{
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
if (await IsLocked() || await stateService.GetPasswordRepromptAutofillAsync())
if (await IsLocked() || await _stateService.Value.GetPasswordRepromptAutofillAsync())
{
PerformSegue("lockPasswordSegue", this);
}
@@ -294,8 +296,7 @@ namespace Bit.iOS.Autofill
private Task<bool> IsAuthed()
{
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
return stateService.IsAuthenticatedAsync();
return _stateService.Value.IsAuthenticatedAsync();
}
private void LogoutIfAuthed()
@@ -304,8 +305,7 @@ namespace Bit.iOS.Autofill
{
if (await IsAuthed())
{
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
await AppHelpers.LogOutAsync(await stateService.GetActiveUserIdAsync());
await AppHelpers.LogOutAsync(await _stateService.Value.GetActiveUserIdAsync());
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
if (deviceActionService.SystemMajorVersion() >= 12)
{
@@ -331,12 +331,16 @@ namespace Bit.iOS.Autofill
Bit.Core.Constants.iOSAutoFillClearCiphersCacheKey, Bit.Core.Constants.iOSAllClearCipherCacheKeys);
iOSCoreHelpers.InitLogger();
iOSCoreHelpers.Bootstrap();
var app = new App.App(new AppOptions { IosExtension = true });
var appOptions = new AppOptions { IosExtension = true };
var app = new App.App(appOptions);
ThemeManager.SetTheme(app.Resources);
iOSCoreHelpers.AppearanceAdjustments();
_nfcDelegate = new Core.NFCReaderDelegate((success, message) =>
messagingService.Send("gotYubiKeyOTP", message));
iOSCoreHelpers.SubscribeBroadcastReceiver(this, _nfcSession, _nfcDelegate);
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
_accountsManager.Init(() => appOptions, this);
}
private void InitAppIfNeeded()
@@ -514,5 +518,35 @@ namespace Bit.iOS.Autofill
updateTempPasswordController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
PresentViewController(updateTempPasswordController, true, null);
}
public Task SetPreviousPageInfoAsync() => Task.CompletedTask;
public Task UpdateThemeAsync() => Task.CompletedTask;
public void Navigate(NavigationTarget navTarget, INavigationParams navParams = null)
{
switch (navTarget)
{
case NavigationTarget.HomeLogin:
DismissViewController(false, () => LaunchHomePage());
break;
case NavigationTarget.Login:
if (navParams is LoginNavigationParams loginParams)
{
DismissViewController(false, () => LaunchLoginFlow(loginParams.Email));
}
else
{
DismissViewController(false, () => LaunchLoginFlow());
}
break;
case NavigationTarget.Lock:
DismissViewController(false, () => PerformSegue("lockPasswordSegue", this));
break;
case NavigationTarget.AutofillCiphers:
case NavigationTarget.Home:
DismissViewController(false, () => PerformSegue("loginListSegue", this));
break;
}
}
}
}